diff --git a/core/src/main/java/ai/timefold/solver/core/api/domain/lookup/PlanningId.java b/core/src/main/java/ai/timefold/solver/core/api/domain/common/PlanningId.java similarity index 96% rename from core/src/main/java/ai/timefold/solver/core/api/domain/lookup/PlanningId.java rename to core/src/main/java/ai/timefold/solver/core/api/domain/common/PlanningId.java index 72afe527674..7537881ae90 100644 --- a/core/src/main/java/ai/timefold/solver/core/api/domain/lookup/PlanningId.java +++ b/core/src/main/java/ai/timefold/solver/core/api/domain/common/PlanningId.java @@ -1,4 +1,4 @@ -package ai.timefold.solver.core.api.domain.lookup; +package ai.timefold.solver.core.api.domain.common; import static java.lang.annotation.ElementType.FIELD; import static java.lang.annotation.ElementType.METHOD; diff --git a/core/src/main/java/ai/timefold/solver/core/api/domain/entity/PinningFilter.java b/core/src/main/java/ai/timefold/solver/core/api/domain/entity/PinningFilter.java deleted file mode 100644 index 98e712e1565..00000000000 --- a/core/src/main/java/ai/timefold/solver/core/api/domain/entity/PinningFilter.java +++ /dev/null @@ -1,26 +0,0 @@ -package ai.timefold.solver.core.api.domain.entity; - -import ai.timefold.solver.core.api.domain.solution.PlanningSolution; - -import org.jspecify.annotations.NullMarked; - -/** - * Decides on accepting or discarding a {@link PlanningEntity}. - * A pinned {@link PlanningEntity}'s planning variables are never changed. - * - * @param the solution type, the class with the {@link PlanningSolution} annotation - * @param the entity type, the class with the {@link PlanningEntity} annotation - * @deprecated Use {@link PlanningPin} instead. - */ -@Deprecated(forRemoval = true, since = "1.23.0") -@NullMarked -public interface PinningFilter { - - /** - * @param solution working solution to which the entity belongs - * @param entity a {@link PlanningEntity} - * @return true if the entity it is pinned, false if the entity is movable. - */ - boolean accept(Solution_ solution, Entity_ entity); - -} diff --git a/core/src/main/java/ai/timefold/solver/core/api/domain/entity/PlanningEntity.java b/core/src/main/java/ai/timefold/solver/core/api/domain/entity/PlanningEntity.java index f041b0b8729..71cb5efc234 100644 --- a/core/src/main/java/ai/timefold/solver/core/api/domain/entity/PlanningEntity.java +++ b/core/src/main/java/ai/timefold/solver/core/api/domain/entity/PlanningEntity.java @@ -10,7 +10,6 @@ import ai.timefold.solver.core.api.domain.common.ComparatorFactory; import ai.timefold.solver.core.api.domain.solution.PlanningSolution; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; -import ai.timefold.solver.core.impl.heuristic.selector.common.decorator.SelectionSorterWeightFactory; /** * Specifies that the class is a planning entity. @@ -69,80 +68,4 @@ interface NullComparator extends Comparator { interface NullComparatorFactory extends ComparatorFactory { } - /** - * A pinned planning entity is never changed during planning, - * this is useful in repeated planning use cases (such as continuous planning and real-time planning). - * This applies to all the planning variables of this planning entity. - *

- * The method {@link PinningFilter#accept(Object, Object)} returns false if the selection entity is pinned - * and it returns true if the selection entity is movable - * - * @return {@link NullPinningFilter} when it is null (workaround for annotation limitation) - * @deprecated Prefer using {@link PlanningPin}. - */ - @Deprecated(forRemoval = true, since = "1.23.0") - Class pinningFilter() default NullPinningFilter.class; - - /** - * Workaround for annotation limitation in {@link #pinningFilter()}. - * - * @deprecated Prefer using {@link PlanningPin}. - */ - @Deprecated(forRemoval = true, since = "1.23.0") - interface NullPinningFilter extends PinningFilter { - } - - /** - * Allows a collection of planning entities to be sorted by difficulty. - * A difficultyWeight estimates how hard is to plan a certain PlanningEntity. - * Some algorithms benefit from planning on more difficult planning entities first/last or from focusing on them. - *

- * The {@link Comparator} should sort in ascending difficulty - * (even though many optimization algorithms will reverse it). - * For example: sorting 3 processes on difficultly based on their RAM usage requirement: - * Process B (1GB RAM), Process A (2GB RAM), Process C (7GB RAM), - *

- * Do not use together with {@link #difficultyWeightFactoryClass()}. - * - * @deprecated Deprecated in favor of {@link #comparatorClass()}. - * - * @return {@link NullDifficultyComparator} when it is null (workaround for annotation limitation) - * @see #difficultyWeightFactoryClass() - */ - @Deprecated(forRemoval = true, since = "1.28.0") - Class difficultyComparatorClass() default NullDifficultyComparator.class; - - /** - * Workaround for annotation limitation in {@link #difficultyComparatorClass()}. - * - * @deprecated Deprecated in favor of {@link NullComparator}. - */ - @Deprecated(forRemoval = true, since = "1.28.0") - interface NullDifficultyComparator extends NullComparator { - } - - /** - * The {@link SelectionSorterWeightFactory} alternative for {@link #difficultyComparatorClass()}. - *

- * Do not use together with {@link #difficultyComparatorClass()}. - * - * @deprecated Deprecated in favor of {@link #comparatorFactoryClass()}. - * - * @return {@link NullDifficultyWeightFactory} when it is null (workaround for annotation limitation) - * @see #difficultyComparatorClass() - */ - @Deprecated(forRemoval = true, since = "1.28.0") - Class difficultyWeightFactoryClass() default NullDifficultyWeightFactory.class; - - /** - * Workaround for annotation limitation in {@link #difficultyWeightFactoryClass()}. - * - * @deprecated Deprecated in favor of {@link NullComparatorFactory}. - */ - @Deprecated(forRemoval = true, since = "1.28.0") - interface NullDifficultyWeightFactory - extends SelectionSorterWeightFactory, - NullComparatorFactory { - } - } diff --git a/core/src/main/java/ai/timefold/solver/core/api/domain/solution/PlanningSolution.java b/core/src/main/java/ai/timefold/solver/core/api/domain/solution/PlanningSolution.java index 2c702d9bf7b..dedd9689bbc 100644 --- a/core/src/main/java/ai/timefold/solver/core/api/domain/solution/PlanningSolution.java +++ b/core/src/main/java/ai/timefold/solver/core/api/domain/solution/PlanningSolution.java @@ -7,8 +7,6 @@ import java.lang.annotation.Target; import ai.timefold.solver.core.api.domain.autodiscover.AutoDiscoverMemberType; -import ai.timefold.solver.core.api.domain.lookup.LookUpStrategyType; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.solution.cloner.SolutionCloner; import ai.timefold.solver.core.api.score.stream.ConstraintProvider; @@ -73,11 +71,4 @@ interface NullSolutionCloner extends SolutionCloner { } - /** - * @deprecated When multi-threaded solving, ensure your domain classes use {@link PlanningId} instead. - */ - @Deprecated(forRemoval = true, since = "1.10.0") - @NonNull - LookUpStrategyType lookUpStrategyType() default LookUpStrategyType.PLANNING_ID_OR_NONE; - } diff --git a/core/src/main/java/ai/timefold/solver/core/api/domain/variable/PlanningVariable.java b/core/src/main/java/ai/timefold/solver/core/api/domain/variable/PlanningVariable.java index 29094956097..1ca35440c4e 100644 --- a/core/src/main/java/ai/timefold/solver/core/api/domain/variable/PlanningVariable.java +++ b/core/src/main/java/ai/timefold/solver/core/api/domain/variable/PlanningVariable.java @@ -12,7 +12,6 @@ import ai.timefold.solver.core.api.domain.entity.PlanningEntity; import ai.timefold.solver.core.api.domain.solution.PlanningSolution; import ai.timefold.solver.core.api.domain.valuerange.ValueRangeProvider; -import ai.timefold.solver.core.impl.heuristic.selector.common.decorator.SelectionSorterWeightFactory; /** * Specifies that a bean property (or a field) can be changed and should be optimized by the optimization algorithms. @@ -84,63 +83,4 @@ interface NullComparator extends Comparator { interface NullComparatorFactory extends ComparatorFactory { } - /** - * As defined by {@link #allowsUnassigned()}. - * - * @deprecated Use {@link #allowsUnassigned()} instead. - * @return true if null is a valid value for this planning variable - */ - @Deprecated(forRemoval = true, since = "1.8.0") - boolean nullable() default false; - - /** - * Allows a collection of planning values for this variable to be sorted by strength. - * A strengthWeight estimates how strong a planning value is. - * Some algorithms benefit from planning on weaker planning values first or from focusing on them. - *

- * The {@link Comparator} should sort in ascending strength. - * For example: sorting 3 computers on strength based on their RAM capacity: - * Computer B (1GB RAM), Computer A (2GB RAM), Computer C (7GB RAM), - *

- * Do not use together with {@link #strengthWeightFactoryClass()}. - * - * @deprecated Deprecated in favor of {@link #comparatorClass()}. - * - * @return {@link NullStrengthComparator} when it is null (workaround for annotation limitation) - * @see #strengthWeightFactoryClass() - */ - @Deprecated(forRemoval = true, since = "1.28.0") - Class strengthComparatorClass() default NullStrengthComparator.class; - - /** - * Workaround for annotation limitation in {@link #strengthComparatorClass()}. - * - * @deprecated Deprecated in favor of {@link NullComparator}. - */ - @Deprecated(forRemoval = true, since = "1.28.0") - interface NullStrengthComparator extends NullComparator { - } - - /** - * The {@link SelectionSorterWeightFactory} alternative for {@link #strengthComparatorClass()}. - *

- * Do not use together with {@link #strengthComparatorClass()}. - * - * @deprecated Deprecated in favor of {@link #comparatorFactoryClass()}. - * - * @return {@link NullStrengthWeightFactory} when it is null (workaround for annotation limitation) - * @see #strengthComparatorClass() - */ - @Deprecated(forRemoval = true, since = "1.28.0") - Class strengthWeightFactoryClass() default NullStrengthWeightFactory.class; - - /** - * Workaround for annotation limitation in {@link #strengthWeightFactoryClass()}. - * - * @deprecated Deprecated in favor of {@link NullComparatorFactory}. - */ - @Deprecated(forRemoval = true, since = "1.28.0") - interface NullStrengthWeightFactory - extends SelectionSorterWeightFactory, NullComparatorFactory { - } } diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/director/ScoreDirector.java b/core/src/main/java/ai/timefold/solver/core/api/score/director/ScoreDirector.java index 02df8237e18..24f17aa8041 100644 --- a/core/src/main/java/ai/timefold/solver/core/api/score/director/ScoreDirector.java +++ b/core/src/main/java/ai/timefold/solver/core/api/score/director/ScoreDirector.java @@ -1,12 +1,11 @@ package ai.timefold.solver.core.api.score.director; -import ai.timefold.solver.core.api.domain.lookup.LookUpStrategyType; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.solution.PlanningSolution; import ai.timefold.solver.core.api.score.Score; import ai.timefold.solver.core.api.solver.change.ProblemChange; -import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; /** @@ -15,6 +14,7 @@ * * @param the solution type, the class with the {@link PlanningSolution} annotation */ +@NullMarked public interface ScoreDirector { /** @@ -23,7 +23,6 @@ public interface ScoreDirector { * Because a {@link Score} is best calculated incrementally (by deltas), * the {@link ScoreDirector} needs to be notified when its {@link PlanningSolution working solution} changes. */ - @NonNull Solution_ getWorkingSolution(); void beforeVariableChanged(Object entity, String variableName); @@ -44,103 +43,12 @@ public interface ScoreDirector { void triggerVariableListeners(); - /** - * @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences. - * Use {@link ProblemChange} instead. - */ - @Deprecated(forRemoval = true, since = "1.8.0") - default void beforeEntityAdded(Object entity) { - throw new UnsupportedOperationException(); - } - - /** - * @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences. - * Use {@link ProblemChange} instead. - */ - @Deprecated(forRemoval = true, since = "1.8.0") - default void afterEntityAdded(Object entity) { - throw new UnsupportedOperationException(); - } - - /** - * @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences. - * Use {@link ProblemChange} instead. - */ - @Deprecated(forRemoval = true, since = "1.8.0") - default void beforeEntityRemoved(Object entity) { - throw new UnsupportedOperationException(); - } - - /** - * @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences. - * Use {@link ProblemChange} instead. - */ - @Deprecated(forRemoval = true, since = "1.8.0") - default void afterEntityRemoved(Object entity) { - throw new UnsupportedOperationException(); - } - - /** - * @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences. - * Use {@link ProblemChange} instead. - */ - @Deprecated(forRemoval = true, since = "1.8.0") - default void beforeProblemFactAdded(Object problemFact) { - throw new UnsupportedOperationException(); - } - - /** - * @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences. - * Use {@link ProblemChange} instead. - */ - @Deprecated(forRemoval = true, since = "1.8.0") - default void afterProblemFactAdded(Object problemFact) { - throw new UnsupportedOperationException(); - } - - /** - * @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences. - * Use {@link ProblemChange} instead. - */ - @Deprecated(forRemoval = true, since = "1.8.0") - default void beforeProblemPropertyChanged(Object problemFactOrEntity) { - throw new UnsupportedOperationException(); - } - - /** - * @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences. - * Use {@link ProblemChange} instead. - */ - @Deprecated(forRemoval = true, since = "1.8.0") - default void afterProblemPropertyChanged(Object problemFactOrEntity) { - throw new UnsupportedOperationException(); - } - - /** - * @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences. - * Use {@link ProblemChange} instead. - */ - @Deprecated(forRemoval = true, since = "1.8.0") - default void beforeProblemFactRemoved(Object problemFact) { - throw new UnsupportedOperationException(); - } - - /** - * @deprecated Calling this method by user code is not recommended and will lead to unforeseen consequences. - * Use {@link ProblemChange} instead. - */ - @Deprecated(forRemoval = true, since = "1.8.0") - default void afterProblemFactRemoved(Object problemFact) { - throw new UnsupportedOperationException(); - } - /** * Translates an entity or fact instance (often from another {@link Thread} or JVM) * to this {@link ScoreDirector}'s internal working instance. * Useful for move rebasing and in a {@link ProblemChange}. *

- * Matching is determined by the {@link LookUpStrategyType} on {@link PlanningSolution}. - * Matching uses a {@link PlanningId} by default. + * Matching uses {@link PlanningId}. * * @return null if externalObject is null * @throws IllegalArgumentException if there is no workingObject for externalObject, if it cannot be looked up @@ -156,7 +64,7 @@ default void afterProblemFactRemoved(Object problemFact) { * It's recommended to use {@link #lookUpWorkingObject(Object)} instead, * especially in move rebasing code. * - * @return null if externalObject is null or if there is no workingObject for externalObject + * @return null if externalObject is null, or if there is no workingObject for externalObject * @throws IllegalArgumentException if it cannot be looked up or if the externalObject's class is not supported * @throws IllegalStateException if it cannot be looked up * @param the object type diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintFactory.java b/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintFactory.java index 49bd6ad088e..009944ca0be 100644 --- a/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintFactory.java +++ b/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintFactory.java @@ -4,8 +4,8 @@ import java.util.function.Function; import java.util.function.Predicate; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.solution.ProblemFactCollectionProperty; import ai.timefold.solver.core.api.domain.variable.InverseRelationShadowVariable; import ai.timefold.solver.core.api.domain.variable.PlanningListVariable; diff --git a/core/src/main/java/ai/timefold/solver/core/api/solver/change/ProblemChangeDirector.java b/core/src/main/java/ai/timefold/solver/core/api/solver/change/ProblemChangeDirector.java index 0f364dc7f9f..1072d299070 100644 --- a/core/src/main/java/ai/timefold/solver/core/api/solver/change/ProblemChangeDirector.java +++ b/core/src/main/java/ai/timefold/solver/core/api/solver/change/ProblemChangeDirector.java @@ -3,14 +3,13 @@ import java.util.Optional; import java.util.function.Consumer; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.LookUpStrategyType; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.solution.PlanningSolution; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; import ai.timefold.solver.core.api.domain.variable.ShadowVariable; -import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; /** @@ -21,6 +20,7 @@ * Should be used only from a {@link ProblemChange} implementation. * To see an example implementation, please refer to the {@link ProblemChange} Javadoc. */ +@NullMarked public interface ProblemChangeDirector { /** @@ -30,7 +30,7 @@ public interface ProblemChangeDirector { * @param entityConsumer adds the entity to the {@link PlanningSolution working solution} * @param the planning entity object type */ - void addEntity(@NonNull Entity entity, @NonNull Consumer entityConsumer); + void addEntity(Entity entity, Consumer entityConsumer); /** * Remove an existing {@link PlanningEntity} instance from the {@link PlanningSolution working solution}. @@ -41,7 +41,7 @@ public interface ProblemChangeDirector { * @param entityConsumer removes the working entity from the {@link PlanningSolution working solution} * @param the planning entity object type */ - void removeEntity(@NonNull Entity entity, @NonNull Consumer entityConsumer); + void removeEntity(Entity entity, Consumer entityConsumer); /** * Change a {@link PlanningVariable} value of a {@link PlanningEntity}. Translates the entity to a working @@ -52,8 +52,7 @@ public interface ProblemChangeDirector { * @param entityConsumer updates the value of the {@link PlanningVariable} inside the {@link PlanningEntity} * @param the planning entity object type */ - void changeVariable(@NonNull Entity entity, @NonNull String variableName, - @NonNull Consumer entityConsumer); + void changeVariable(Entity entity, String variableName, Consumer entityConsumer); /** * Add a new problem fact into the {@link PlanningSolution working solution}. @@ -63,7 +62,7 @@ void changeVariable(@NonNull Entity entity, @NonNull String variableNam * {@link PlanningSolution working solution} * @param the problem fact object type */ - void addProblemFact(@NonNull ProblemFact problemFact, @NonNull Consumer problemFactConsumer); + void addProblemFact(ProblemFact problemFact, Consumer problemFactConsumer); /** * Remove an existing problem fact from the {@link PlanningSolution working solution}. Translates the problem fact @@ -74,7 +73,7 @@ void changeVariable(@NonNull Entity entity, @NonNull String variableNam * {@link PlanningSolution working solution} * @param the problem fact object type */ - void removeProblemFact(@NonNull ProblemFact problemFact, @NonNull Consumer problemFactConsumer); + void removeProblemFact(ProblemFact problemFact, Consumer problemFactConsumer); /** * Change a property of either a {@link PlanningEntity} or a problem fact. Translates the entity or the problem fact @@ -86,15 +85,14 @@ void changeVariable(@NonNull Entity entity, @NonNull String variableNam * or the problem fact * @param the planning entity or problem fact object type */ - void changeProblemProperty(@NonNull EntityOrProblemFact problemFactOrEntity, - @NonNull Consumer problemFactOrEntityConsumer); + void changeProblemProperty(EntityOrProblemFact problemFactOrEntity, + Consumer problemFactOrEntityConsumer); /** * Translate an entity or fact instance (often from another {@link Thread} or JVM) * to this {@link ProblemChangeDirector}'s internal working instance. *

- * Matching is determined by the {@link LookUpStrategyType} on {@link PlanningSolution}. - * Matching uses a {@link PlanningId} by default. + * Matching uses {@link PlanningId}. * * @return null if externalObject is null * @throws IllegalArgumentException if there is no workingObject for externalObject, if it cannot be looked up @@ -109,7 +107,7 @@ void changeProblemProperty(@NonNull EntityOrProblemFact pr * but doesn't fail fast if no workingObject was ever added for the externalObject. * It's recommended to use {@link #lookUpWorkingObjectOrFail(Object)} instead. * - * @return {@link Optional#empty()} if externalObject is null or if there is no workingObject for externalObject + * @return {@link Optional#empty()} if there is no workingObject for externalObject, or if externalObject is null * @throws IllegalArgumentException if it cannot be looked up or if the externalObject's class is not supported * @throws IllegalStateException if it cannot be looked up * @param the object type 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 52c09eb78a0..3575d050d4d 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 @@ -1,7 +1,6 @@ package ai.timefold.solver.core.config.util; import static ai.timefold.solver.core.impl.domain.common.accessor.MemberAccessorFactory.MemberAccessorType.FIELD_OR_READ_METHOD; -import static ai.timefold.solver.core.impl.domain.solution.cloner.DeepCloningUtils.IMMUTABLE_CLASSES; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; @@ -32,7 +31,7 @@ import java.util.stream.Stream; import ai.timefold.solver.core.api.domain.common.DomainAccessType; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.config.AbstractConfig; import ai.timefold.solver.core.impl.domain.common.AlphabeticMemberComparator; import ai.timefold.solver.core.impl.domain.common.ReflectionHelper; @@ -451,17 +450,6 @@ Maybe the member (%s) should return a parameterized %s.""" memberName, type, memberName, type.getSimpleName()))); } - /** - * @param type the class type - * @return true if it is immutable; otherwise false - */ - public static boolean isGenericTypeImmutable(Class type) { - if (type == null) { - return false; - } - return type.isRecord() || IMMUTABLE_CLASSES.contains(type); - } - public static Optional> extractGenericTypeParameter(@NonNull String parentClassConcept, @NonNull Class parentClass, @NonNull Class type, @NonNull Type genericType, @Nullable Class annotationClass, @NonNull String memberName) { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/domain/entity/descriptor/EntityDescriptor.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/entity/descriptor/EntityDescriptor.java index b191ea49a75..46495afc4b5 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/domain/entity/descriptor/EntityDescriptor.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/domain/entity/descriptor/EntityDescriptor.java @@ -23,7 +23,6 @@ import java.util.function.Consumer; import java.util.function.Predicate; -import ai.timefold.solver.core.api.domain.entity.PinningFilter; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; import ai.timefold.solver.core.api.domain.entity.PlanningPin; import ai.timefold.solver.core.api.domain.entity.PlanningPinToIndex; @@ -100,7 +99,6 @@ public class EntityDescriptor { private ShadowVariablesInconsistentVariableDescriptor shadowVariablesInconsistentDescriptor; // Only declared movable filter, excludes inherited and descending movable filters - private MovableFilter declaredMovableEntityFilter; private SelectionSorter descendingSorter; // Only declared variable descriptors, excludes inherited variable descriptors @@ -232,87 +230,35 @@ private void processEntityAnnotations() { .orElseThrow( () -> new IllegalStateException("Impossible state as the previous if block would fail first.")); } - processMovable(entityAnnotation); processSorting(entityAnnotation); } - /** - * @deprecated Remove in the next major version of Timefold Solver. - */ - @Deprecated(forRemoval = true, since = "1.23.0") - private void processMovable(PlanningEntity entityAnnotation) { - if (entityAnnotation == null) { - return; - } - var pinningFilterClass = entityAnnotation.pinningFilter(); - var hasPinningFilter = pinningFilterClass != PlanningEntity.NullPinningFilter.class; - if (hasPinningFilter) { - var pinningFilter = ConfigUtils.newInstance(this::toString, "pinningFilterClass", - (Class>) pinningFilterClass); - declaredMovableEntityFilter = (solution, selection) -> !pinningFilter.accept(solution, selection); - } - } - private void processSorting(PlanningEntity entityAnnotation) { if (entityAnnotation == null) { return; } - var difficultyComparatorClass = entityAnnotation.difficultyComparatorClass(); - if (difficultyComparatorClass != null - && PlanningEntity.NullComparator.class.isAssignableFrom(difficultyComparatorClass)) { - difficultyComparatorClass = null; - } var comparatorClass = entityAnnotation.comparatorClass(); if (comparatorClass != null && PlanningEntity.NullComparator.class.isAssignableFrom(comparatorClass)) { comparatorClass = null; } - if (difficultyComparatorClass != null && comparatorClass != null) { - throw new IllegalStateException( - "The entityClass (%s) cannot have a %s (%s) and a %s (%s) at the same time.".formatted(getEntityClass(), - "difficultyComparatorClass", difficultyComparatorClass.getName(), "comparatorClass", - comparatorClass.getName())); - } - var difficultyWeightFactoryClass = entityAnnotation.difficultyWeightFactoryClass(); - if (difficultyWeightFactoryClass != null - && PlanningEntity.NullComparatorFactory.class.isAssignableFrom(difficultyWeightFactoryClass)) { - difficultyWeightFactoryClass = null; - } var comparatorFactoryClass = entityAnnotation.comparatorFactoryClass(); if (comparatorFactoryClass != null && PlanningEntity.NullComparatorFactory.class.isAssignableFrom(comparatorFactoryClass)) { comparatorFactoryClass = null; } - if (difficultyWeightFactoryClass != null && comparatorFactoryClass != null) { + // Selected settings + if (comparatorClass != null && comparatorFactoryClass != null) { throw new IllegalStateException( - "The entityClass (%s) cannot have a %s (%s) and a %s (%s) at the same time.".formatted(getEntityClass(), - "difficultyWeightFactoryClass", difficultyWeightFactoryClass.getName(), "comparatorFactoryClass", - comparatorFactoryClass.getName())); + "The entityClass (%s) cannot have a comparatorClass (%s) and a comparatorFactoryClass (%s) at the same time." + .formatted(entityClass, comparatorClass.getName(), comparatorFactoryClass.getName())); } - // Selected settings - var selectedComparatorPropertyName = "comparatorClass"; - var selectedComparatorClass = comparatorClass; - var selectedComparatorFactoryPropertyName = "comparatorFactoryClass"; - var selectedComparatorFactoryClass = comparatorFactoryClass; - if (difficultyComparatorClass != null) { - selectedComparatorPropertyName = "difficultyComparatorClass"; - selectedComparatorClass = difficultyComparatorClass; - } - if (difficultyWeightFactoryClass != null) { - selectedComparatorFactoryPropertyName = "difficultyWeightFactoryClass"; - selectedComparatorFactoryClass = difficultyWeightFactoryClass; - } - if (selectedComparatorClass != null && selectedComparatorFactoryClass != null) { - throw new IllegalStateException("The entityClass (%s) cannot have a %s (%s) and a %s (%s) at the same time." - .formatted(entityClass, selectedComparatorPropertyName, selectedComparatorClass.getName(), - selectedComparatorFactoryPropertyName, selectedComparatorFactoryClass.getName())); - } - if (selectedComparatorClass != null) { - var comparator = ConfigUtils.newInstance(this::toString, selectedComparatorPropertyName, selectedComparatorClass); + if (comparatorClass != null) { + var comparator = ConfigUtils.newInstance(this::toString, "comparatorClass", comparatorClass); descendingSorter = new ComparatorSelectionSorter<>(comparator, SelectionSorterOrder.DESCENDING); - } else if (selectedComparatorFactoryClass != null) { - var comparator = ConfigUtils.newInstance(this::toString, selectedComparatorFactoryPropertyName, - selectedComparatorFactoryClass); + } else if (comparatorFactoryClass != null) { + var comparator = ConfigUtils.newInstance(this::toString, "comparatorFactoryClass", + comparatorFactoryClass); descendingSorter = new ComparatorFactorySelectionSorter<>(comparator, SelectionSorterOrder.DESCENDING); } } @@ -552,11 +498,6 @@ Maybe remove the variables (%s) from the class (%s).""".formatted(entityClass, } private void createEffectiveMovableEntitySelectionFilter() { - if (declaredMovableEntityFilter != null && !hasAnyDeclaredGenuineVariableDescriptor()) { - throw new IllegalStateException( - "The entityClass (%s) has a movableEntitySelectionFilterClass (%s), but it has no declared genuine variables, only shadow variables." - .formatted(entityClass, declaredMovableEntityFilter.getClass())); - } var movableFilterList = new ArrayList>(); // TODO Also add in child entity selectors for (var inheritedEntityDescriptor : effectiveInheritedEntityDescriptorList) { @@ -565,9 +506,6 @@ private void createEffectiveMovableEntitySelectionFilter() { movableFilterList.add(inheritedEntityDescriptor.effectiveMovableEntityFilter); } } - if (declaredMovableEntityFilter != null) { - movableFilterList.add(declaredMovableEntityFilter); - } movableFilterList.addAll(declaredPinEntityFilterList); if (movableFilterList.isEmpty()) { effectiveMovableEntityFilter = null; @@ -637,10 +575,6 @@ public boolean matchesEntity(Object entity) { return entityClass.isAssignableFrom(entity.getClass()); } - public boolean hasPinningFilter() { - return declaredMovableEntityFilter != null; - } - public boolean hasEffectiveMovableEntityFilter() { return effectiveMovableEntityFilter != null; } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/EqualsLookUpStrategy.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/EqualsLookUpStrategy.java deleted file mode 100644 index 00ae5f9af11..00000000000 --- a/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/EqualsLookUpStrategy.java +++ /dev/null @@ -1,46 +0,0 @@ -package ai.timefold.solver.core.impl.domain.lookup; - -import java.util.Map; - -import ai.timefold.solver.core.api.domain.solution.ProblemFactCollectionProperty; - -public final class EqualsLookUpStrategy implements LookUpStrategy { - - @Override - public void addWorkingObject(Map idToWorkingObjectMap, Object workingObject) { - Object oldAddedObject = idToWorkingObjectMap.put(workingObject, workingObject); - if (oldAddedObject != null) { - throw new IllegalStateException("The workingObjects (" + oldAddedObject + ", " + workingObject - + ") are equal (as in Object.equals()). Working objects must be unique."); - } - } - - @Override - public void removeWorkingObject(Map idToWorkingObjectMap, Object workingObject) { - Object removedObject = idToWorkingObjectMap.remove(workingObject); - if (workingObject != removedObject) { - throw new IllegalStateException("The workingObject (" + workingObject - + ") differs from the removedObject (" + removedObject + ")."); - } - } - - @Override - public E lookUpWorkingObject(Map idToWorkingObjectMap, E externalObject) { - E workingObject = (E) idToWorkingObjectMap.get(externalObject); - if (workingObject == null) { - throw new IllegalStateException("The externalObject (" + externalObject - + ") has no known workingObject (" + workingObject + ").\n" - + "Maybe the workingObject was never added because the planning solution doesn't have a @" - + ProblemFactCollectionProperty.class.getSimpleName() - + " annotation on a member with instances of the externalObject's class (" - + externalObject.getClass() + ")."); - } - return workingObject; - } - - @Override - public E lookUpWorkingObjectIfExists(Map idToWorkingObjectMap, E externalObject) { - return (E) idToWorkingObjectMap.get(externalObject); - } - -} diff --git a/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/ImmutableLookUpStrategy.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/ImmutableLookUpStrategy.java index b9966e7be26..bf3bafaa18c 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/ImmutableLookUpStrategy.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/ImmutableLookUpStrategy.java @@ -2,7 +2,10 @@ import java.util.Map; -public final class ImmutableLookUpStrategy implements LookUpStrategy { +import org.jspecify.annotations.NullMarked; + +@NullMarked +final class ImmutableLookUpStrategy implements LookUpStrategy { @Override public void addWorkingObject(Map idToWorkingObjectMap, Object workingObject) { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/LookUpManager.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/LookUpManager.java index 0997f6b907a..83ded2e7e5c 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/LookUpManager.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/LookUpManager.java @@ -3,70 +3,70 @@ import java.util.HashMap; import java.util.Map; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.score.director.ScoreDirector; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + /** * @see PlanningId * @see ScoreDirector#lookUpWorkingObject(Object) */ -public class LookUpManager { +@NullMarked +public final class LookUpManager { private final LookUpStrategyResolver lookUpStrategyResolver; - - private Map idToWorkingObjectMap; + private final Map idToWorkingObjectMap = new HashMap<>(); public LookUpManager(LookUpStrategyResolver lookUpStrategyResolver) { this.lookUpStrategyResolver = lookUpStrategyResolver; - reset(); } public void reset() { - idToWorkingObjectMap = new HashMap<>(); + idToWorkingObjectMap.clear(); } public void addWorkingObject(Object workingObject) { - LookUpStrategy lookUpStrategy = lookUpStrategyResolver.determineLookUpStrategy(workingObject); + var lookUpStrategy = lookUpStrategyResolver.determineLookUpStrategy(workingObject); lookUpStrategy.addWorkingObject(idToWorkingObjectMap, workingObject); } public void removeWorkingObject(Object workingObject) { - LookUpStrategy lookUpStrategy = lookUpStrategyResolver.determineLookUpStrategy(workingObject); + var lookUpStrategy = lookUpStrategyResolver.determineLookUpStrategy(workingObject); lookUpStrategy.removeWorkingObject(idToWorkingObjectMap, workingObject); } /** * As defined by {@link ScoreDirector#lookUpWorkingObject(Object)}. * - * @param externalObject sometimes null * @return null if externalObject is null * @throws IllegalArgumentException if there is no workingObject for externalObject, if it cannot be looked up * or if the externalObject's class is not supported * @throws IllegalStateException if it cannot be looked up * @param the object type */ - public E lookUpWorkingObject(E externalObject) { + public @Nullable E lookUpWorkingObject(@Nullable E externalObject) { if (externalObject == null) { return null; } - LookUpStrategy lookUpStrategy = lookUpStrategyResolver.determineLookUpStrategy(externalObject); + var lookUpStrategy = lookUpStrategyResolver.determineLookUpStrategy(externalObject); return lookUpStrategy.lookUpWorkingObject(idToWorkingObjectMap, externalObject); } /** * As defined by {@link ScoreDirector#lookUpWorkingObjectOrReturnNull(Object)}. * - * @param externalObject sometimes null - * @return null if externalObject is null or if there is no workingObject for externalObject + * @return null if externalObject is null, or if there is no workingObject for externalObject * @throws IllegalArgumentException if it cannot be looked up or if the externalObject's class is not supported * @throws IllegalStateException if it cannot be looked up * @param the object type */ - public E lookUpWorkingObjectOrReturnNull(E externalObject) { + public @Nullable E lookUpWorkingObjectOrReturnNull(@Nullable E externalObject) { if (externalObject == null) { return null; } - LookUpStrategy lookUpStrategy = lookUpStrategyResolver.determineLookUpStrategy(externalObject); + var lookUpStrategy = lookUpStrategyResolver.determineLookUpStrategy(externalObject); return lookUpStrategy.lookUpWorkingObjectIfExists(idToWorkingObjectMap, externalObject); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategy.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategy.java index 3915fce0516..8672b61f152 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategy.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategy.java @@ -2,8 +2,12 @@ import java.util.Map; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked public sealed interface LookUpStrategy - permits EqualsLookUpStrategy, ImmutableLookUpStrategy, NoneLookUpStrategy, PlanningIdLookUpStrategy { + permits ImmutableLookUpStrategy, NoneLookUpStrategy, PlanningIdLookUpStrategy { void addWorkingObject(Map idToWorkingObjectMap, Object workingObject); @@ -11,6 +15,6 @@ public sealed interface LookUpStrategy E lookUpWorkingObject(Map idToWorkingObjectMap, E externalObject); - E lookUpWorkingObjectIfExists(Map idToWorkingObjectMap, E externalObject); + @Nullable E lookUpWorkingObjectIfExists(Map idToWorkingObjectMap, E externalObject); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyResolver.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyResolver.java index ea55257d715..8f70cfb4486 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyResolver.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyResolver.java @@ -1,91 +1,80 @@ package ai.timefold.solver.core.impl.domain.lookup; -import java.lang.reflect.Method; -import java.util.concurrent.ConcurrentMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import ai.timefold.solver.core.api.domain.common.DomainAccessType; -import ai.timefold.solver.core.api.domain.lookup.LookUpStrategyType; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; -import ai.timefold.solver.core.api.domain.solution.PlanningSolution; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.config.util.ConfigUtils; import ai.timefold.solver.core.impl.domain.common.accessor.MemberAccessorFactory; import ai.timefold.solver.core.impl.domain.policy.DescriptorPolicy; import ai.timefold.solver.core.impl.domain.solution.cloner.DeepCloningUtils; -import ai.timefold.solver.core.impl.util.ConcurrentMemoization; + +import org.jspecify.annotations.NullMarked; /** * This class is thread-safe. */ +@NullMarked public final class LookUpStrategyResolver { private final LookUpStrategyType lookUpStrategyType; private final DomainAccessType domainAccessType; private final MemberAccessorFactory memberAccessorFactory; - private final ConcurrentMap, LookUpStrategy> decisionCache = new ConcurrentMemoization<>(); + private final Map, LookUpStrategy> decisionCache = new ConcurrentHashMap<>(); + + public LookUpStrategyResolver(DescriptorPolicy descriptorPolicy) { + this(descriptorPolicy, LookUpStrategyType.PLANNING_ID_OR_NONE); + } - public LookUpStrategyResolver(DescriptorPolicy descriptorPolicy, LookUpStrategyType lookUpStrategyType) { + LookUpStrategyResolver(DescriptorPolicy descriptorPolicy, LookUpStrategyType lookUpStrategyType) { this.lookUpStrategyType = lookUpStrategyType; this.domainAccessType = descriptorPolicy.getDomainAccessType(); this.memberAccessorFactory = descriptorPolicy.getMemberAccessorFactory(); } /** - * This method is thread-safe. + * This method is thread-safe, + * in a sense that it can be called by multiple threads at the same time, + * and it will always return the same result for the same input. * * @param object never null * @return never null */ public LookUpStrategy determineLookUpStrategy(Object object) { - return decisionCache.computeIfAbsent(object.getClass(), objectClass -> { + var objectClass = object.getClass(); + var decision = decisionCache.get(objectClass); + if (decision == null) { // Simulate computeIfAbsent, avoiding creating a lambda on the hot path. if (DeepCloningUtils.isImmutable(objectClass)) { - return new ImmutableLookUpStrategy(); - } - return switch (lookUpStrategyType) { - case PLANNING_ID_OR_NONE -> { - var memberAccessor = - ConfigUtils.findPlanningIdMemberAccessor(objectClass, memberAccessorFactory, domainAccessType); - if (memberAccessor == null) { - yield new NoneLookUpStrategy(); + decision = new ImmutableLookUpStrategy(); + } else { + decision = switch (lookUpStrategyType) { + case NONE -> new NoneLookUpStrategy(); + case PLANNING_ID_OR_NONE -> { + var memberAccessor = + ConfigUtils.findPlanningIdMemberAccessor(objectClass, memberAccessorFactory, domainAccessType); + if (memberAccessor == null) { + yield new NoneLookUpStrategy(); + } + yield new PlanningIdLookUpStrategy(memberAccessor); } - yield new PlanningIdLookUpStrategy(memberAccessor); - } - case PLANNING_ID_OR_FAIL_FAST -> { - var memberAccessor = - ConfigUtils.findPlanningIdMemberAccessor(objectClass, memberAccessorFactory, domainAccessType); - if (memberAccessor == null) { - throw new IllegalArgumentException("The class (" + objectClass - + ") does not have a @" + PlanningId.class.getSimpleName() + " annotation," - + " but the lookUpStrategyType (" + lookUpStrategyType + ") requires it.\n" - + "Maybe add the @" + PlanningId.class.getSimpleName() + " annotation" - + " or change the @" + PlanningSolution.class.getSimpleName() + " annotation's " - + LookUpStrategyType.class.getSimpleName() + "."); + case PLANNING_ID_OR_FAIL_FAST -> { + var memberAccessor = + ConfigUtils.findPlanningIdMemberAccessor(objectClass, memberAccessorFactory, domainAccessType); + if (memberAccessor == null) { + throw new IllegalArgumentException(""" + The class (%s) does not have a @%s annotation, but the lookUpStrategyType (%s) requires it. + Maybe add a @%s annotation?""" + .formatted(objectClass, PlanningId.class.getSimpleName(), lookUpStrategyType, + PlanningId.class.getSimpleName())); + } + yield new PlanningIdLookUpStrategy(memberAccessor); } - yield new PlanningIdLookUpStrategy(memberAccessor); - } - case EQUALITY -> { - Method equalsMethod; - Method hashCodeMethod; - try { - equalsMethod = objectClass.getMethod("equals", Object.class); - hashCodeMethod = objectClass.getMethod("hashCode"); - } catch (NoSuchMethodException e) { - throw new IllegalStateException( - "Impossible state because equals() and hashCode() always exist.", e); - } - if (equalsMethod.getDeclaringClass().equals(Object.class)) { - throw new IllegalArgumentException("The class (" + objectClass.getSimpleName() - + ") doesn't override the equals() method, neither does any superclass."); - } - if (hashCodeMethod.getDeclaringClass().equals(Object.class)) { - throw new IllegalArgumentException("The class (" + objectClass.getSimpleName() - + ") overrides equals() but neither it nor any superclass" - + " overrides the hashCode() method."); - } - yield new EqualsLookUpStrategy(); - } - case NONE -> new NoneLookUpStrategy(); - }; - }); + }; + decisionCache.put(objectClass, decision); + } + } + return decision; } } diff --git a/core/src/main/java/ai/timefold/solver/core/api/domain/lookup/LookUpStrategyType.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyType.java similarity index 56% rename from core/src/main/java/ai/timefold/solver/core/api/domain/lookup/LookUpStrategyType.java rename to core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyType.java index d51db7dfdcd..92a33b6c092 100644 --- a/core/src/main/java/ai/timefold/solver/core/api/domain/lookup/LookUpStrategyType.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyType.java @@ -1,5 +1,6 @@ -package ai.timefold.solver.core.api.domain.lookup; +package ai.timefold.solver.core.impl.domain.lookup; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; import ai.timefold.solver.core.api.domain.solution.ProblemFactCollectionProperty; import ai.timefold.solver.core.api.score.director.ScoreDirector; @@ -8,11 +9,9 @@ * Determines how {@link ScoreDirector#lookUpWorkingObject(Object)} maps * a {@link ProblemFactCollectionProperty problem fact} or a {@link PlanningEntity planning entity} * from an external copy to the internal one. - * - * @deprecated When multi-threaded solving, ensure your domain classes use {@link PlanningId} instead. */ -@Deprecated(forRemoval = true, since = "1.10.0") -public enum LookUpStrategyType { +enum LookUpStrategyType { + /** * Map by the same {@link PlanningId} field or method. * If there is no such field or method, @@ -28,14 +27,7 @@ public enum LookUpStrategyType { */ PLANNING_ID_OR_FAIL_FAST, /** - * Map by {@link Object#equals(Object) equals(Object)} and {@link Object#hashCode() hashCode()}. - * If any of these two methods is not overridden by the working object's class or some of its superclasses, - * {@link ScoreDirector#lookUpWorkingObject(Object)} must not be used because it cannot work correctly with - * {@link Object}'s equals and hashCode implementations. - */ - EQUALITY, - /** - * There is no mapping and {@link ScoreDirector#lookUpWorkingObject(Object)} must not be used. + * Only used in testing; do not use in production code. */ NONE; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/NoneLookUpStrategy.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/NoneLookUpStrategy.java index a3b0b924709..a1028e946c9 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/NoneLookUpStrategy.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/NoneLookUpStrategy.java @@ -2,11 +2,12 @@ import java.util.Map; -import ai.timefold.solver.core.api.domain.lookup.LookUpStrategyType; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; -import ai.timefold.solver.core.api.domain.solution.PlanningSolution; +import ai.timefold.solver.core.api.domain.common.PlanningId; -public final class NoneLookUpStrategy implements LookUpStrategy { +import org.jspecify.annotations.NullMarked; + +@NullMarked +final class NoneLookUpStrategy implements LookUpStrategy { @Override public void addWorkingObject(Map idToWorkingObjectMap, Object workingObject) { @@ -20,22 +21,16 @@ public void removeWorkingObject(Map idToWorkingObjectMap, Object @Override public E lookUpWorkingObject(Map idToWorkingObjectMap, E externalObject) { - throw new IllegalArgumentException("The externalObject (" + externalObject - + ") cannot be looked up. Some functionality, such as multithreaded solving, requires this ability.\n" - + "Maybe add a @" + PlanningId.class.getSimpleName() - + " annotation on an identifier property of the class (" + externalObject.getClass() + ").\n" - + "Or otherwise, maybe change the @" + PlanningSolution.class.getSimpleName() + " annotation's " - + LookUpStrategyType.class.getSimpleName() + " (not recommended)."); + throw new IllegalArgumentException(""" + The externalObject (%s) cannot be looked up. + Some functionality, such as multithreaded solving, requires this ability. + Maybe add a @%s annotation on an identifier property of the class (%s).""" + .formatted(externalObject, PlanningId.class.getSimpleName(), externalObject.getClass())); } @Override public E lookUpWorkingObjectIfExists(Map idToWorkingObjectMap, E externalObject) { - throw new IllegalArgumentException("The externalObject (" + externalObject - + ") cannot be looked up. Some functionality, such as multithreaded solving, requires this ability.\n" - + "Maybe add a @" + PlanningId.class.getSimpleName() - + " annotation on an identifier property of the class (" + externalObject.getClass() + ").\n" - + "Or otherwise, maybe change the @" + PlanningSolution.class.getSimpleName() + " annotation's " - + LookUpStrategyType.class.getSimpleName() + " (not recommended)."); + return lookUpWorkingObject(idToWorkingObjectMap, externalObject); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/PlanningIdLookUpStrategy.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/PlanningIdLookUpStrategy.java index 5bcac0898fb..568cd31a5c3 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/PlanningIdLookUpStrategy.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/PlanningIdLookUpStrategy.java @@ -2,14 +2,15 @@ import java.util.Map; -import ai.timefold.solver.core.api.domain.lookup.LookUpStrategyType; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; -import ai.timefold.solver.core.api.domain.solution.PlanningSolution; import ai.timefold.solver.core.api.domain.solution.ProblemFactCollectionProperty; import ai.timefold.solver.core.impl.domain.common.accessor.MemberAccessor; import ai.timefold.solver.core.impl.util.Pair; -public final class PlanningIdLookUpStrategy implements LookUpStrategy { +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked +final class PlanningIdLookUpStrategy implements LookUpStrategy { private final MemberAccessor planningIdMemberAccessor; @@ -22,8 +23,10 @@ public void addWorkingObject(Map idToWorkingObjectMap, Object wo var planningId = extractPlanningId(workingObject); var oldAddedObject = idToWorkingObjectMap.put(planningId, workingObject); if (oldAddedObject != null) { - throw new IllegalStateException("The workingObjects (" + oldAddedObject + ", " + workingObject - + ") have the same planningId (" + planningId + "). Working objects must be unique."); + throw new IllegalStateException(""" + The workingObjects (%s, %s) have the same planningId (%s). + Working objects must be unique.""" + .formatted(oldAddedObject, workingObject, planningId)); } } @@ -32,28 +35,30 @@ public void removeWorkingObject(Map idToWorkingObjectMap, Object var planningId = extractPlanningId(workingObject); var removedObject = idToWorkingObjectMap.remove(planningId); if (workingObject != removedObject) { - throw new IllegalStateException("The workingObject (" + workingObject - + ") differs from the removedObject (" + removedObject + ") for planningId (" + planningId + ")."); + throw new IllegalStateException("The workingObject (%s) differs from the removedObject (%s) for planningId (%s)." + .formatted(workingObject, removedObject, planningId)); } } + @SuppressWarnings("unchecked") @Override public E lookUpWorkingObject(Map idToWorkingObjectMap, E externalObject) { var planningId = extractPlanningId(externalObject); - var workingObject = (E) idToWorkingObjectMap.get(planningId); + var workingObject = idToWorkingObjectMap.get(planningId); if (workingObject == null) { - throw new IllegalStateException("The externalObject (" + externalObject + ") with planningId (" + planningId - + ") has no known workingObject (" + workingObject + ").\n" - + "Maybe the workingObject was never added because the planning solution doesn't have a @" - + ProblemFactCollectionProperty.class.getSimpleName() - + " annotation on a member with instances of the externalObject's class (" - + externalObject.getClass() + ")."); + throw new IllegalStateException(""" + The externalObject (%s) with planningId (%s) has no known workingObject (%s). + Maybe the workingObject was never added because the planning solution doesn't have a @%s annotation \ + on a member with instances of the externalObject's class (%s).""" + .formatted(externalObject, planningId, workingObject, ProblemFactCollectionProperty.class.getSimpleName(), + externalObject.getClass())); } - return workingObject; + return (E) workingObject; } + @SuppressWarnings("unchecked") @Override - public E lookUpWorkingObjectIfExists(Map idToWorkingObjectMap, E externalObject) { + public @Nullable E lookUpWorkingObjectIfExists(Map idToWorkingObjectMap, E externalObject) { var planningId = extractPlanningId(externalObject); return (E) idToWorkingObjectMap.get(planningId); } @@ -61,15 +66,11 @@ public E lookUpWorkingObjectIfExists(Map idToWorkingObjectMa private Pair, Object> extractPlanningId(Object externalObject) { var planningId = planningIdMemberAccessor.executeGetter(externalObject); if (planningId == null) { - throw new IllegalArgumentException("The planningId (" + planningId - + ") of the member (" + planningIdMemberAccessor + ") of the class (" + externalObject.getClass() - + ") on externalObject (" + externalObject - + ") must not be null.\n" - + "Maybe initialize the planningId of the class (" + externalObject.getClass().getSimpleName() - + ") instance (" + externalObject + ") before solving.\n" + - "Maybe remove the @" + PlanningId.class.getSimpleName() + " annotation" - + " or change the @" + PlanningSolution.class.getSimpleName() + " annotation's " - + LookUpStrategyType.class.getSimpleName() + "."); + throw new IllegalArgumentException(""" + The planningId (%s) of the member (%s) of the class (%s) on externalObject (%s) must not be null. + Maybe initialize the planningId of the class (%s) instance (%s) before solving.""" + .formatted(planningId, planningIdMemberAccessor, externalObject.getClass(), externalObject, + externalObject.getClass().getSimpleName(), externalObject)); } return new Pair<>(externalObject.getClass(), planningId); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/package-info.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/package-info.java deleted file mode 100644 index bdbaec51244..00000000000 --- a/core/src/main/java/ai/timefold/solver/core/impl/domain/lookup/package-info.java +++ /dev/null @@ -1,6 +0,0 @@ -/** - * @deprecated When multi-threaded solving, - * ensure your domain classes use {@link ai.timefold.solver.core.api.domain.lookup.PlanningId} instead. - */ -@Deprecated(forRemoval = true, since = "1.10.0") -package ai.timefold.solver.core.impl.domain.lookup; \ No newline at end of file diff --git a/core/src/main/java/ai/timefold/solver/core/impl/domain/solution/cloner/DeepCloningUtils.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/solution/cloner/DeepCloningUtils.java index 0c959a2fc25..64b6c3cebb6 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/domain/solution/cloner/DeepCloningUtils.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/domain/solution/cloner/DeepCloningUtils.java @@ -29,7 +29,7 @@ import java.util.Set; import java.util.UUID; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.solution.cloner.DeepPlanningClone; import ai.timefold.solver.core.api.domain.variable.PlanningListVariable; import ai.timefold.solver.core.api.score.Score; @@ -39,7 +39,7 @@ public final class DeepCloningUtils { // Instances of these JDK classes will never be deep-cloned. - public static final Set> IMMUTABLE_CLASSES = Set.of( + private static final Set> VALUE_CLASSES = Set.of( // Numbers Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, BigInteger.class, BigDecimal.class, // Optional @@ -112,7 +112,7 @@ The class (%s) is annotated with @%s, but it is immutable. } return true; } - return IMMUTABLE_CLASSES.contains(clz); + return VALUE_CLASSES.contains(clz); } /** diff --git a/core/src/main/java/ai/timefold/solver/core/impl/domain/solution/cloner/gizmo/GizmoCloningUtils.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/solution/cloner/gizmo/GizmoCloningUtils.java index 4ff3825813e..c6bf0a2db50 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/domain/solution/cloner/gizmo/GizmoCloningUtils.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/domain/solution/cloner/gizmo/GizmoCloningUtils.java @@ -46,7 +46,7 @@ public static Set> getDeepClonedClasses(SolutionDescriptor solutionD } } - // Ignore Collections, Maps, and PlanningCloneables, as there is collection/map/clonable logic to clone them. + // Ignore Collections and Maps, as there is collection/map/clonable logic to clone them. if (DeepCloningUtils.isFieldDeepCloned(solutionDescriptor, field, clazz) && !Collection.class.isAssignableFrom(field.getType()) && !Map.class.isAssignableFrom(field.getType()) diff --git a/core/src/main/java/ai/timefold/solver/core/impl/domain/solution/descriptor/SolutionDescriptor.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/solution/descriptor/SolutionDescriptor.java index 58b9c3fb2fb..6e7e38af6dc 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/domain/solution/descriptor/SolutionDescriptor.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/domain/solution/descriptor/SolutionDescriptor.java @@ -387,9 +387,7 @@ private void processSolutionAnnotations(DescriptorPolicy descriptorPolicy) { if (solutionClonerClass != PlanningSolution.NullSolutionCloner.class) { solutionCloner = ConfigUtils.newInstance(this::toString, "solutionClonerClass", solutionClonerClass); } - var lookUpStrategyType = annotation.lookUpStrategyType(); - lookUpStrategyResolver = - new LookUpStrategyResolver(descriptorPolicy, lookUpStrategyType); + lookUpStrategyResolver = new LookUpStrategyResolver(descriptorPolicy); } private @NonNull PlanningSolution extractMostRelevantPlanningSolutionAnnotation() { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/ShadowVariableUpdateHelper.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/ShadowVariableUpdateHelper.java index 9097203086c..f6986766797 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/ShadowVariableUpdateHelper.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/ShadowVariableUpdateHelper.java @@ -317,6 +317,7 @@ public InternalScoreDirectorFactory(SolutionDescriptor solutionDescri } } + @NullMarked private static class InternalScoreDirector> extends AbstractScoreDirector> { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/descriptor/BasicVariableDescriptor.java b/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/descriptor/BasicVariableDescriptor.java index dab24a5746a..352823e3789 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/descriptor/BasicVariableDescriptor.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/domain/variable/descriptor/BasicVariableDescriptor.java @@ -40,78 +40,32 @@ protected void processPropertyAnnotations(DescriptorPolicy descriptorPolicy) { sortingProperties.comparatorFactoryPropertyName(), sortingProperties.comparatorFactoryClass()); } - private SortingProperties assertSortingProperties(PlanningVariable planningVariableAnnotation) { + private static SortingProperties assertSortingProperties(PlanningVariable planningVariableAnnotation) { // Comparator property - var strengthComparatorClass = planningVariableAnnotation.strengthComparatorClass(); var comparatorClass = planningVariableAnnotation.comparatorClass(); - if (strengthComparatorClass != null - && PlanningVariable.NullComparator.class.isAssignableFrom(strengthComparatorClass)) { - strengthComparatorClass = null; - } if (comparatorClass != null && PlanningVariable.NullComparator.class.isAssignableFrom(comparatorClass)) { comparatorClass = null; } - if (strengthComparatorClass != null && comparatorClass != null) { - throw new IllegalStateException( - "The entityClass (%s) property (%s) cannot have a %s (%s) and a %s (%s) at the same time.".formatted( - entityDescriptor.getEntityClass(), variableMemberAccessor.getName(), "strengthComparatorClass", - strengthComparatorClass.getName(), "comparatorClass", comparatorClass.getName())); - } // Comparator factory property - var strengthWeightFactoryClass = planningVariableAnnotation.strengthWeightFactoryClass(); var comparatorFactoryClass = planningVariableAnnotation.comparatorFactoryClass(); - if (strengthWeightFactoryClass != null - && PlanningVariable.NullComparatorFactory.class.isAssignableFrom(strengthWeightFactoryClass)) { - strengthWeightFactoryClass = null; - } if (comparatorFactoryClass != null && PlanningVariable.NullComparatorFactory.class.isAssignableFrom(comparatorFactoryClass)) { comparatorFactoryClass = null; } - if (strengthWeightFactoryClass != null && comparatorFactoryClass != null) { - throw new IllegalStateException( - "The entityClass (%s) property (%s) cannot have a %s (%s) and a %s (%s) at the same time.".formatted( - entityDescriptor.getEntityClass(), variableMemberAccessor.getName(), "strengthWeightFactoryClass", - strengthWeightFactoryClass.getName(), "comparatorFactoryClass", comparatorFactoryClass.getName())); - } // Selected settings - var selectedComparatorPropertyName = "comparatorClass"; - var selectedComparatorClass = comparatorClass; - var selectedComparatorFactoryPropertyName = "comparatorFactoryClass"; - var selectedComparatorFactoryClass = comparatorFactoryClass; - if (strengthComparatorClass != null) { - selectedComparatorPropertyName = "strengthComparatorClass"; - selectedComparatorClass = strengthComparatorClass; - } - if (strengthWeightFactoryClass != null) { - selectedComparatorFactoryPropertyName = "strengthWeightFactoryClass"; - selectedComparatorFactoryClass = strengthWeightFactoryClass; - } - return new SortingProperties(selectedComparatorPropertyName, selectedComparatorClass, - selectedComparatorFactoryPropertyName, selectedComparatorFactoryClass); + return new SortingProperties("comparatorClass", comparatorClass, + "comparatorFactoryClass", comparatorFactoryClass); } private void processAllowsUnassigned(PlanningVariable planningVariableAnnotation) { - var deprecatedNullable = planningVariableAnnotation.nullable(); - if (planningVariableAnnotation.allowsUnassigned()) { - // If the user has specified allowsUnassigned = true, it takes precedence. - if (deprecatedNullable) { - throw new IllegalArgumentException( - "The entityClass (%s) has a @%s-annotated property (%s) with allowsUnassigned (%s) and nullable (%s) which are mutually exclusive." - .formatted(entityDescriptor.getEntityClass(), PlanningVariable.class.getSimpleName(), - variableMemberAccessor.getName(), true, true)); - } - this.allowsUnassigned = true; - } else { // If the user has not specified allowsUnassigned = true, nullable is taken. - this.allowsUnassigned = deprecatedNullable; - } - if (this.allowsUnassigned && variableMemberAccessor.getType().isPrimitive()) { + allowsUnassigned = planningVariableAnnotation.allowsUnassigned(); + if (allowsUnassigned && variableMemberAccessor.getType().isPrimitive()) { throw new IllegalArgumentException( "The entityClass (%s) has a @%s-annotated property (%s) with allowsUnassigned (%s) which is not compatible with the primitive propertyType (%s)." .formatted(entityDescriptor.getEntityClass(), PlanningVariable.class.getSimpleName(), variableMemberAccessor.getName(), - this.allowsUnassigned, + allowsUnassigned, variableMemberAccessor.getType())); } } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/heuristic/move/Move.java b/core/src/main/java/ai/timefold/solver/core/impl/heuristic/move/Move.java index 4b423a686b3..98b348743ad 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/heuristic/move/Move.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/heuristic/move/Move.java @@ -2,8 +2,8 @@ import java.util.Iterator; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.solution.PlanningSolution; import ai.timefold.solver.core.api.domain.solution.ProblemFactProperty; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/move/MoveTesterScoreDirector.java b/core/src/main/java/ai/timefold/solver/core/impl/move/MoveTesterScoreDirector.java index 84c974fcc4c..d13a8d9461f 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/move/MoveTesterScoreDirector.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/move/MoveTesterScoreDirector.java @@ -11,6 +11,7 @@ import org.jspecify.annotations.NullMarked; +@NullMarked final class MoveTesterScoreDirector> extends AbstractScoreDirector> { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/move/VariableChangeRecordingScoreDirector.java b/core/src/main/java/ai/timefold/solver/core/impl/move/VariableChangeRecordingScoreDirector.java index 006aa053cd4..fe2390fb3cc 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/move/VariableChangeRecordingScoreDirector.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/move/VariableChangeRecordingScoreDirector.java @@ -17,10 +17,14 @@ import ai.timefold.solver.core.impl.score.director.ValueRangeManager; import ai.timefold.solver.core.impl.score.director.VariableDescriptorCache; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked public final class VariableChangeRecordingScoreDirector> implements RevertableScoreDirector { - private final InnerScoreDirector backingScoreDirector; + private final @Nullable InnerScoreDirector backingScoreDirector; private final List> variableChanges; /* @@ -40,7 +44,7 @@ public final class VariableChangeRecordingScoreDirector cache; + private final @Nullable Map cache; public VariableChangeRecordingScoreDirector(ScoreDirector backingScoreDirector) { this(backingScoreDirector, true); @@ -54,8 +58,8 @@ public VariableChangeRecordingScoreDirector(ScoreDirector backingScor this.variableChanges = new LinkedList<>(); } - private VariableChangeRecordingScoreDirector(InnerScoreDirector backingScoreDirector, - List> variableChanges, Map cache) { + private VariableChangeRecordingScoreDirector(@Nullable InnerScoreDirector backingScoreDirector, + List> variableChanges, @Nullable Map cache) { this.backingScoreDirector = backingScoreDirector; this.variableChanges = variableChanges; this.cache = cache; @@ -176,13 +180,13 @@ public SolutionDescriptor getSolutionDescriptor() { @Override public ValueRangeManager getValueRangeManager() { - return getBacking().getValueRangeManager(); + return Objects.requireNonNull(getBacking()).getValueRangeManager(); } /** * Returns the score director to which events are delegated. */ - public InnerScoreDirector getBacking() { + public @Nullable InnerScoreDirector getBacking() { return backingScoreDirector; } @@ -215,12 +219,12 @@ public void triggerVariableListeners() { } @Override - public E lookUpWorkingObject(E externalObject) { + public @Nullable E lookUpWorkingObject(@Nullable E externalObject) { return Objects.requireNonNull(backingScoreDirector).lookUpWorkingObject(externalObject); } @Override - public E lookUpWorkingObjectOrReturnNull(E externalObject) { + public @Nullable E lookUpWorkingObjectOrReturnNull(@Nullable E externalObject) { return Objects.requireNonNull(backingScoreDirector).lookUpWorkingObjectOrReturnNull(externalObject); } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/partitionedsearch/partitioner/SolutionPartitioner.java b/core/src/main/java/ai/timefold/solver/core/impl/partitionedsearch/partitioner/SolutionPartitioner.java index e0884bab0bb..a40b2519104 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/partitionedsearch/partitioner/SolutionPartitioner.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/partitionedsearch/partitioner/SolutionPartitioner.java @@ -2,6 +2,7 @@ import java.util.List; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; import ai.timefold.solver.core.api.domain.solution.PlanningSolution; import ai.timefold.solver.core.api.domain.solution.cloner.SolutionCloner; @@ -9,7 +10,7 @@ /** * Splits one {@link PlanningSolution solution} into multiple partitions. - * The partitions are solved and merged based on the {@link PlanningSolution#lookUpStrategyType()}. + * The partitions are solved and merged based on {@link PlanningId}. *

* To add custom properties, configure custom properties and add public setters for them. * diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/director/AbstractScoreDirector.java b/core/src/main/java/ai/timefold/solver/core/impl/score/director/AbstractScoreDirector.java index 58655cfe3a7..9a2b125808c 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/director/AbstractScoreDirector.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/director/AbstractScoreDirector.java @@ -48,7 +48,6 @@ import ai.timefold.solver.core.preview.api.move.Move; import ai.timefold.solver.core.preview.api.move.SolutionView; -import org.jspecify.annotations.NonNull; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; @@ -65,8 +64,9 @@ *

  • after* method: first statement should be a call to the super method
  • * */ +@NullMarked public abstract class AbstractScoreDirector, Factory_ extends AbstractScoreDirectorFactory> - implements InnerScoreDirector, Cloneable { + implements InnerScoreDirector { private static final int CONSTRAINT_MATCH_DISPLAY_LIMIT = 8; protected final Logger logger = LoggerFactory.getLogger(getClass()); @@ -79,7 +79,7 @@ public abstract class AbstractScoreDirector neighborhoodsElementUpdateNotifier; private final boolean lookUpEnabled; - private final LookUpManager lookUpManager; + private final @Nullable LookUpManager lookUpManager; protected final ConstraintMatchPolicy constraintMatchPolicy; private boolean expectShadowVariablesInCorrectState; private final VariableDescriptorCache variableDescriptorCache; @@ -93,14 +93,14 @@ public abstract class AbstractScoreDirector valueRangeManager; - private final ListVariableStateSupply listVariableStateSupply; // Null when no list variable. + private final @Nullable ListVariableStateSupply listVariableStateSupply; // Null when no list variable. private final MoveDirector moveDirector = new MoveDirector<>(this); private long workingEntityListRevision = 0L; private int workingGenuineEntityCount = 0; private boolean allChangesWillBeUndoneBeforeStepEnds = false; private long calculationCount = 0L; - protected Solution_ workingSolution; + protected @Nullable Solution_ workingSolution; private int workingInitScore = 0; private final boolean isStepAssertOrMore; @@ -178,7 +178,7 @@ public boolean expectShadowVariablesInCorrectState() { } @Override - public @NonNull Solution_ getWorkingSolution() { + public Solution_ getWorkingSolution() { return workingSolution; } @@ -251,7 +251,8 @@ public NeighborhoodNotifier getNeighborhoodNotifier() { * @param workingSolution the working solution to set * @param entityAndFactVisitor maybe null; a function to apply to all problem facts and problem entities */ - protected void setWorkingSolutionWithoutUpdatingShadows(Solution_ workingSolution, Consumer entityAndFactVisitor) { + protected void setWorkingSolutionWithoutUpdatingShadows(Solution_ workingSolution, + @Nullable Consumer entityAndFactVisitor) { this.workingSolution = requireNonNull(workingSolution); var solutionDescriptor = getSolutionDescriptor(); @@ -443,15 +444,6 @@ protected void setCalculatedScore(Score_ score) { calculationCount++; } - /** - * @deprecated Unused, but kept for backward compatibility. - */ - @Deprecated(forRemoval = true, since = "1.14.0") - @Override - public AbstractScoreDirector clone() { - throw new UnsupportedOperationException("Cloning score directors is not supported."); - } - @Override public InnerScoreDirector createChildThreadScoreDirector(ChildThreadType childThreadType) { // Most score directors don't need derived status; CS will override this. @@ -885,7 +877,7 @@ private void assertValueRangeForListVariable(Object entity, List valueLi } private static void assertValueRangeForBasicVariables(InnerScoreDirector scoreDirector, - List> basicVariableDescriptorList, Object entity) { + @Nullable List> basicVariableDescriptorList, Object entity) { if (basicVariableDescriptorList == null || basicVariableDescriptorList.isEmpty()) { return; } @@ -905,7 +897,7 @@ private static void assertValueRangeForBasicVariables(InnerScoreDire } private static void assertValueRangeForListVariable(InnerScoreDirector scoreDirector, - ListVariableDescriptor variableDescriptor, Object entity, List valueList) { + ListVariableDescriptor variableDescriptor, Object entity, List<@Nullable Object> valueList) { if (valueList.isEmpty()) { return; } @@ -923,36 +915,6 @@ private static void assertValueRangeForListVariable(InnerScoreDirect } } - public SolutionTracker.SolutionCorruptionResult getSolutionCorruptionAfterUndo(Move move, - InnerScore undoInnerScore) { - var trackingWorkingSolution = solutionTracker != null; - if (trackingWorkingSolution) { - solutionTracker.setAfterUndoSolution(workingSolution); - } - // Precondition: assert that there are probably no corrupted constraints - var undoMoveToString = "Undo(%s)".formatted(move); - assertWorkingScoreFromScratch(undoInnerScore, undoMoveToString); - // Precondition: assert that shadow variables aren't stale after doing the undoMove - assertShadowVariablesAreNotStale(undoInnerScore, undoMoveToString); - if (trackingWorkingSolution) { - // Recalculate all shadow variables from scratch. - // We cannot set all shadow variables to null, since some variable listeners - // may expect them to be non-null. - // Instead, we just simulate a change to all genuine variables. - variableListenerSupport.forceTriggerAllVariableListeners(workingSolution); - solutionTracker.setUndoFromScratchSolution(workingSolution); - - // Also calculate from scratch for the before solution, since it might - // have been corrupted but was only detected now - solutionTracker.restoreBeforeSolution(); - variableListenerSupport.forceTriggerAllVariableListeners(workingSolution); - solutionTracker.setBeforeFromScratchSolution(workingSolution); - - return solutionTracker.buildSolutionCorruptionResult(); - } - return SolutionTracker.SolutionCorruptionResult.untracked(); - } - /** * @param uncorruptedScoreDirector never null * @param predicted true if the score was predicted and might have been calculated on another thread @@ -1028,11 +990,15 @@ Maybe there is a bug in the score constraints of those ConstraintMatch(s). } private static > List> - emptyMatchAnalysisIfNull(ConstraintAnalysis constraintAnalysis) { + emptyMatchAnalysisIfNull(@Nullable ConstraintAnalysis constraintAnalysis) { if (constraintAnalysis == null) { return Collections.emptyList(); } - return Objects.requireNonNullElse(constraintAnalysis.matches(), Collections.emptyList()); + var matches = constraintAnalysis.matches(); + if (matches == null) { + return Collections.emptyList(); + } + return matches; } private void appendAnalysis(StringBuilder analysis, String workingLabel, String suffix, diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/director/InnerScoreDirector.java b/core/src/main/java/ai/timefold/solver/core/impl/score/director/InnerScoreDirector.java index 9b1f719ef46..71134c5dd8f 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/director/InnerScoreDirector.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/director/InnerScoreDirector.java @@ -41,12 +41,14 @@ import ai.timefold.solver.core.preview.api.move.Move; import ai.timefold.solver.core.preview.api.move.SolutionView; +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; /** * @param the solution type, the class with the {@link PlanningSolution} annotation * @param the score type to go with the solution */ +@NullMarked public interface InnerScoreDirector> extends VariableDescriptorAwareScoreDirector, AutoCloseable { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/director/RevertableScoreDirector.java b/core/src/main/java/ai/timefold/solver/core/impl/score/director/RevertableScoreDirector.java index 1a319ad911f..245b3c25d16 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/director/RevertableScoreDirector.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/director/RevertableScoreDirector.java @@ -2,6 +2,9 @@ import java.util.List; +import org.jspecify.annotations.NullMarked; + +@NullMarked public interface RevertableScoreDirector extends VariableDescriptorAwareScoreDirector { /** diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/director/VariableDescriptorAwareScoreDirector.java b/core/src/main/java/ai/timefold/solver/core/impl/score/director/VariableDescriptorAwareScoreDirector.java index ce1401616d3..dbbad741b15 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/director/VariableDescriptorAwareScoreDirector.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/director/VariableDescriptorAwareScoreDirector.java @@ -5,6 +5,9 @@ import ai.timefold.solver.core.impl.domain.variable.descriptor.ListVariableDescriptor; import ai.timefold.solver.core.impl.domain.variable.descriptor.VariableDescriptor; +import org.jspecify.annotations.NullMarked; + +@NullMarked public interface VariableDescriptorAwareScoreDirector extends ScoreDirector { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/director/easy/EasyScoreDirector.java b/core/src/main/java/ai/timefold/solver/core/impl/score/director/easy/EasyScoreDirector.java index 46e7a0b552d..baceb3b1c72 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/director/easy/EasyScoreDirector.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/director/easy/EasyScoreDirector.java @@ -28,6 +28,7 @@ * @param the score type to go with the solution * @see ScoreDirector */ +@NullMarked public final class EasyScoreDirector> extends AbstractScoreDirector> { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/director/incremental/IncrementalScoreDirector.java b/core/src/main/java/ai/timefold/solver/core/impl/score/director/incremental/IncrementalScoreDirector.java index 942a1a26737..576e3b6b589 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/director/incremental/IncrementalScoreDirector.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/director/incremental/IncrementalScoreDirector.java @@ -35,6 +35,7 @@ * @param the score type to go with the solution * @see ScoreDirector */ +@NullMarked public final class IncrementalScoreDirector> extends AbstractScoreDirector> { @@ -142,13 +143,13 @@ public void afterEntityAdded(EntityDescriptor entityDescriptor, Objec } @Override - public void beforeVariableChanged(VariableDescriptor variableDescriptor, Object entity) { + public void beforeVariableChanged(VariableDescriptor variableDescriptor, Object entity) { incrementalScoreCalculator.beforeVariableChanged(entity, variableDescriptor.getVariableName()); super.beforeVariableChanged(variableDescriptor, entity); } @Override - public void afterVariableChanged(VariableDescriptor variableDescriptor, Object entity) { + public void afterVariableChanged(VariableDescriptor variableDescriptor, Object entity) { incrementalScoreCalculator.afterVariableChanged(entity, variableDescriptor.getVariableName()); super.afterVariableChanged(variableDescriptor, entity); } @@ -270,7 +271,7 @@ public IncrementalScoreDirector build() { } private static ConstraintMatchPolicy determineCorrectPolicy(ConstraintMatchPolicy constraintMatchPolicy, - IncrementalScoreCalculator incrementalScoreCalculator) { + @Nullable IncrementalScoreCalculator incrementalScoreCalculator) { if (incrementalScoreCalculator instanceof ConstraintMatchAwareIncrementalScoreCalculator) { return constraintMatchPolicy; } else { diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/director/stream/BavetConstraintStreamScoreDirector.java b/core/src/main/java/ai/timefold/solver/core/impl/score/director/stream/BavetConstraintStreamScoreDirector.java index 9a969b0fc07..fab45272199 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/director/stream/BavetConstraintStreamScoreDirector.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/director/stream/BavetConstraintStreamScoreDirector.java @@ -2,6 +2,7 @@ import java.util.ArrayList; import java.util.Map; +import java.util.Objects; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; import ai.timefold.solver.core.api.domain.solution.PlanningSolution; @@ -18,6 +19,7 @@ import ai.timefold.solver.core.impl.score.stream.bavet.BavetConstraintSession; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; /** * FP streams implementation of {@link ScoreDirector}, which only recalculates the {@link Score} @@ -27,11 +29,12 @@ * @param the solution type, the class with the {@link PlanningSolution} annotation * @see ScoreDirector */ +@NullMarked public final class BavetConstraintStreamScoreDirector> extends AbstractScoreDirector> { private final boolean derived; - private BavetConstraintSession session; + private @Nullable BavetConstraintSession session; private BavetConstraintStreamScoreDirector(Builder builder, boolean derived) { super(builder); @@ -140,9 +143,6 @@ public void close() { @Override public void afterEntityAdded(EntityDescriptor entityDescriptor, Object entity) { - if (entity == null) { - throw new IllegalArgumentException("The entity (%s) cannot be added to the ScoreDirector.".formatted(entity)); - } if (!getSolutionDescriptor().hasEntityDescriptor(entity.getClass())) { throw new IllegalArgumentException("The entity (%s) of class (%s) is not a configured @%s.".formatted(entity, entity.getClass(), PlanningEntity.class.getSimpleName())); @@ -182,11 +182,7 @@ public void afterEntityRemoved(EntityDescriptor entityDescriptor, Obj @Override public void afterProblemFactAdded(Object problemFact) { - if (problemFact == null) { - throw new IllegalArgumentException( - "The problemFact (%s) cannot be added to the ScoreDirector.".formatted(problemFact)); - } - session.insert(problemFact); + session.insert(Objects.requireNonNull(problemFact)); super.afterProblemFactAdded(problemFact); } @@ -218,7 +214,7 @@ public void afterProblemFactRemoved(Object problemFact) { * @return null before first {@link #setWorkingSolutionWithoutUpdatingShadows(Object)} or after {@link #close()}. */ @SuppressWarnings("unused") - public BavetConstraintSession getSession() { + public @Nullable BavetConstraintSession getSession() { return session; } diff --git a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/InnerConstraintFactory.java b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/InnerConstraintFactory.java index 354d097d12b..89a53c29d55 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/InnerConstraintFactory.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/score/stream/common/InnerConstraintFactory.java @@ -11,7 +11,7 @@ import java.util.function.Function; import java.util.stream.Collectors; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.score.constraint.ConstraintRef; import ai.timefold.solver.core.api.score.stream.Constraint; import ai.timefold.solver.core.api.score.stream.ConstraintFactory; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/solver/DefaultSolver.java b/core/src/main/java/ai/timefold/solver/core/impl/solver/DefaultSolver.java index 0c8b9571890..695703a2d68 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/solver/DefaultSolver.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/solver/DefaultSolver.java @@ -6,7 +6,7 @@ import java.util.Objects; import java.util.concurrent.atomic.AtomicBoolean; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.solution.PlanningSolution; import ai.timefold.solver.core.api.solver.Solver; import ai.timefold.solver.core.api.solver.change.ProblemChange; diff --git a/core/src/main/java/ai/timefold/solver/core/impl/solver/DefaultSolverFactory.java b/core/src/main/java/ai/timefold/solver/core/impl/solver/DefaultSolverFactory.java index 97badc78807..12b29585f57 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/solver/DefaultSolverFactory.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/solver/DefaultSolverFactory.java @@ -116,7 +116,7 @@ public > ScoreDirectorFactory ge metricsRequiringConstraintMatchSet); } var castScoreDirector = scoreDirectorFactory.createScoreDirectorBuilder() - .withLookUpEnabled(true) + .withLookUpEnabled(true) // Custom phases and problem changes may rely on lookups. .withConstraintMatchPolicy( constraintMatchEnabled ? ConstraintMatchPolicy.ENABLED : ConstraintMatchPolicy.DISABLED) .build(); diff --git a/core/src/main/java/ai/timefold/solver/core/impl/solver/change/DefaultProblemChangeDirector.java b/core/src/main/java/ai/timefold/solver/core/impl/solver/change/DefaultProblemChangeDirector.java index a885ceb617a..4037dcebd2f 100644 --- a/core/src/main/java/ai/timefold/solver/core/impl/solver/change/DefaultProblemChangeDirector.java +++ b/core/src/main/java/ai/timefold/solver/core/impl/solver/change/DefaultProblemChangeDirector.java @@ -7,9 +7,10 @@ import ai.timefold.solver.core.api.solver.change.ProblemChangeDirector; import ai.timefold.solver.core.impl.score.director.InnerScoreDirector; -import org.jspecify.annotations.NonNull; +import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; +@NullMarked public final class DefaultProblemChangeDirector implements ProblemChangeDirector { private final InnerScoreDirector scoreDirector; @@ -21,7 +22,7 @@ public DefaultProblemChangeDirector(InnerScoreDirector scoreDirect } @Override - public void addEntity(@NonNull Entity entity, @NonNull Consumer entityConsumer) { + public void addEntity(Entity entity, Consumer entityConsumer) { Objects.requireNonNull(entity, () -> "Entity (" + entity + ") cannot be null."); Objects.requireNonNull(entityConsumer, () -> "Entity consumer (" + entityConsumer + ") cannot be null."); scoreDirector.beforeEntityAdded(entity); @@ -31,7 +32,7 @@ public void addEntity(@NonNull Entity entity, @NonNull Consumer } @Override - public void removeEntity(@NonNull Entity entity, @NonNull Consumer entityConsumer) { + public void removeEntity(Entity entity, Consumer entityConsumer) { Objects.requireNonNull(entity, () -> "Entity (" + entity + ") cannot be null."); Objects.requireNonNull(entityConsumer, () -> "Entity consumer (" + entityConsumer + ") cannot be null."); var workingEntity = lookUpWorkingObjectOrFail(entity); @@ -42,8 +43,7 @@ public void removeEntity(@NonNull Entity entity, @NonNull Consumer void changeVariable(@NonNull Entity entity, @NonNull String variableName, - @NonNull Consumer entityConsumer) { + public void changeVariable(Entity entity, String variableName, Consumer entityConsumer) { Objects.requireNonNull(entity, () -> "Entity (" + entity + ") cannot be null."); Objects.requireNonNull(variableName, () -> "Planning variable name (" + variableName + ") cannot be null."); Objects.requireNonNull(entityConsumer, () -> "Entity consumer (" + entityConsumer + ") cannot be null."); @@ -54,22 +54,20 @@ public void changeVariable(@NonNull Entity entity, @NonNull String vari } @Override - public void addProblemFact(@NonNull ProblemFact problemFact, - @NonNull Consumer problemFactConsumer) { + public void addProblemFact(ProblemFact problemFact, Consumer problemFactConsumer) { Objects.requireNonNull(problemFact, () -> "Problem fact (" + problemFact + ") cannot be null."); - Objects.requireNonNull(problemFactConsumer, () -> "Problem fact consumer (" + problemFactConsumer - + ") cannot be null."); + Objects.requireNonNull(problemFactConsumer, + () -> "Problem fact consumer (" + problemFactConsumer + ") cannot be null."); scoreDirector.beforeProblemFactAdded(problemFact); problemFactConsumer.accept(problemFact); scoreDirector.afterProblemFactAdded(problemFact); } @Override - public void removeProblemFact(@NonNull ProblemFact problemFact, - @NonNull Consumer problemFactConsumer) { + public void removeProblemFact(ProblemFact problemFact, Consumer problemFactConsumer) { Objects.requireNonNull(problemFact, () -> "Problem fact (" + problemFact + ") cannot be null."); - Objects.requireNonNull(problemFactConsumer, () -> "Problem fact consumer (" + problemFactConsumer - + ") cannot be null."); + Objects.requireNonNull(problemFactConsumer, + () -> "Problem fact consumer (" + problemFactConsumer + ") cannot be null."); var workingProblemFact = lookUpWorkingObjectOrFail(problemFact); scoreDirector.beforeProblemFactRemoved(workingProblemFact); problemFactConsumer.accept(workingProblemFact); @@ -77,12 +75,12 @@ public void removeProblemFact(@NonNull ProblemFact problemFact, } @Override - public void changeProblemProperty(@NonNull EntityOrProblemFact problemFactOrEntity, - @NonNull Consumer problemFactOrEntityConsumer) { + public void changeProblemProperty(EntityOrProblemFact problemFactOrEntity, + Consumer problemFactOrEntityConsumer) { Objects.requireNonNull(problemFactOrEntity, () -> "Problem fact or entity (" + problemFactOrEntity + ") cannot be null."); - Objects.requireNonNull(problemFactOrEntityConsumer, () -> "Problem fact or entity consumer (" - + problemFactOrEntityConsumer + ") cannot be null."); + Objects.requireNonNull(problemFactOrEntityConsumer, + () -> "Problem fact or entity consumer (" + problemFactOrEntityConsumer + ") cannot be null."); var workingEntityOrProblemFact = lookUpWorkingObjectOrFail(problemFactOrEntity); scoreDirector.beforeProblemPropertyChanged(workingEntityOrProblemFact); problemFactOrEntityConsumer.accept(workingEntityOrProblemFact); @@ -97,7 +95,7 @@ public void changeProblemProperty(@NonNull EntityOrProblem @Override public Optional - lookUpWorkingObject(EntityOrProblemFact externalObject) { + lookUpWorkingObject(@Nullable EntityOrProblemFact externalObject) { return Optional.ofNullable(scoreDirector.lookUpWorkingObjectOrReturnNull(externalObject)); } diff --git a/core/src/main/java/ai/timefold/solver/core/preview/api/move/Move.java b/core/src/main/java/ai/timefold/solver/core/preview/api/move/Move.java index 5aad2b242cd..fb67588058b 100644 --- a/core/src/main/java/ai/timefold/solver/core/preview/api/move/Move.java +++ b/core/src/main/java/ai/timefold/solver/core/preview/api/move/Move.java @@ -5,8 +5,8 @@ import java.util.LinkedHashSet; import java.util.List; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.solution.PlanningSolution; import ai.timefold.solver.core.api.domain.solution.ProblemFactProperty; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; diff --git a/core/src/main/java/ai/timefold/solver/core/preview/api/move/Rebaser.java b/core/src/main/java/ai/timefold/solver/core/preview/api/move/Rebaser.java index d0740cd3e93..0456a793527 100644 --- a/core/src/main/java/ai/timefold/solver/core/preview/api/move/Rebaser.java +++ b/core/src/main/java/ai/timefold/solver/core/preview/api/move/Rebaser.java @@ -1,8 +1,6 @@ package ai.timefold.solver.core.preview.api.move; -import ai.timefold.solver.core.api.domain.lookup.LookUpStrategyType; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; -import ai.timefold.solver.core.api.domain.solution.PlanningSolution; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.score.director.ScoreDirector; import ai.timefold.solver.core.api.solver.change.ProblemChange; @@ -31,8 +29,7 @@ public interface Rebaser { * to another {@link ScoreDirector}'s internal working instance. * Useful for move rebasing and in a {@link ProblemChange} and for multi-threaded solving. *

    - * Matching is determined by the {@link LookUpStrategyType} on {@link PlanningSolution}. - * Matching uses a {@link PlanningId} by default. + * Matching uses {@link PlanningId}. * * @param problemFactOrPlanningEntity The fact or entity to rebase. * @return null if problemFactOrPlanningEntity is null diff --git a/core/src/test/java/ai/timefold/solver/core/config/solver/testutil/corruptedundoshadow/CorruptedUndoShadowEntity.java b/core/src/test/java/ai/timefold/solver/core/config/solver/testutil/corruptedundoshadow/CorruptedUndoShadowEntity.java index df3be938143..e093e6d3e76 100644 --- a/core/src/test/java/ai/timefold/solver/core/config/solver/testutil/corruptedundoshadow/CorruptedUndoShadowEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/config/solver/testutil/corruptedundoshadow/CorruptedUndoShadowEntity.java @@ -2,8 +2,8 @@ import java.util.Objects; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; import ai.timefold.solver.core.api.domain.variable.ShadowSources; import ai.timefold.solver.core.api.domain.variable.ShadowVariable; diff --git a/core/src/test/java/ai/timefold/solver/core/config/solver/testutil/corruptedundoshadow/CorruptedUndoShadowValue.java b/core/src/test/java/ai/timefold/solver/core/config/solver/testutil/corruptedundoshadow/CorruptedUndoShadowValue.java index 4c2671461e9..2282b966570 100644 --- a/core/src/test/java/ai/timefold/solver/core/config/solver/testutil/corruptedundoshadow/CorruptedUndoShadowValue.java +++ b/core/src/test/java/ai/timefold/solver/core/config/solver/testutil/corruptedundoshadow/CorruptedUndoShadowValue.java @@ -3,8 +3,8 @@ import java.util.ArrayList; import java.util.List; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.InverseRelationShadowVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/impl/constructionheuristic/DefaultConstructionHeuristicPhaseTest.java b/core/src/test/java/ai/timefold/solver/core/impl/constructionheuristic/DefaultConstructionHeuristicPhaseTest.java index 291c0f4da5f..0335a8cf1cf 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/constructionheuristic/DefaultConstructionHeuristicPhaseTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/constructionheuristic/DefaultConstructionHeuristicPhaseTest.java @@ -74,27 +74,9 @@ import ai.timefold.solver.core.testdomain.sort.comparator.OneValuePerEntityComparatorEasyScoreCalculator; import ai.timefold.solver.core.testdomain.sort.comparator.TestdataComparatorSortableEntity; import ai.timefold.solver.core.testdomain.sort.comparator.TestdataComparatorSortableSolution; -import ai.timefold.solver.core.testdomain.sort.comparatordifficulty.OneValuePerEntityDifficultyEasyScoreCalculator; -import ai.timefold.solver.core.testdomain.sort.comparatordifficulty.TestdataDifficultySortableEntity; -import ai.timefold.solver.core.testdomain.sort.comparatordifficulty.TestdataDifficultySortableSolution; import ai.timefold.solver.core.testdomain.sort.factory.OneValuePerEntityFactoryEasyScoreCalculator; import ai.timefold.solver.core.testdomain.sort.factory.TestdataFactorySortableEntity; import ai.timefold.solver.core.testdomain.sort.factory.TestdataFactorySortableSolution; -import ai.timefold.solver.core.testdomain.sort.factorydifficulty.OneValuePerEntityDifficultyFactoryEasyScoreCalculator; -import ai.timefold.solver.core.testdomain.sort.factorydifficulty.TestdataDifficultyFactorySortableEntity; -import ai.timefold.solver.core.testdomain.sort.factorydifficulty.TestdataDifficultyFactorySortableSolution; -import ai.timefold.solver.core.testdomain.sort.invalid.mixed.comparator.TestdataInvalidMixedComparatorSortableEntity; -import ai.timefold.solver.core.testdomain.sort.invalid.mixed.comparator.TestdataInvalidMixedComparatorSortableSolution; -import ai.timefold.solver.core.testdomain.sort.invalid.mixed.strength.TestdataInvalidMixedStrengthSortableEntity; -import ai.timefold.solver.core.testdomain.sort.invalid.mixed.strength.TestdataInvalidMixedStrengthSortableSolution; -import ai.timefold.solver.core.testdomain.sort.invalid.twocomparator.entity.TestdataInvalidTwoEntityComparatorSortableEntity; -import ai.timefold.solver.core.testdomain.sort.invalid.twocomparator.entity.TestdataInvalidTwoEntityComparatorSortableSolution; -import ai.timefold.solver.core.testdomain.sort.invalid.twocomparator.value.TestdataInvalidTwoValueComparatorSortableEntity; -import ai.timefold.solver.core.testdomain.sort.invalid.twocomparator.value.TestdataInvalidTwoValueComparatorSortableSolution; -import ai.timefold.solver.core.testdomain.sort.invalid.twofactory.entity.TestdataInvalidTwoEntityFactorySortableEntity; -import ai.timefold.solver.core.testdomain.sort.invalid.twofactory.entity.TestdataInvalidTwoEntityFactorySortableSolution; -import ai.timefold.solver.core.testdomain.sort.invalid.twofactory.value.TestdataInvalidTwoValueFactorySortableEntity; -import ai.timefold.solver.core.testdomain.sort.invalid.twofactory.value.TestdataInvalidTwoValueFactorySortableSolution; import ai.timefold.solver.core.testdomain.unassignedvar.TestdataAllowsUnassignedEasyScoreCalculator; import ai.timefold.solver.core.testdomain.unassignedvar.TestdataAllowsUnassignedEntity; import ai.timefold.solver.core.testdomain.unassignedvar.TestdataAllowsUnassignedSolution; @@ -104,15 +86,9 @@ import ai.timefold.solver.core.testdomain.valuerange.sort.comparator.OneValuePerEntityComparatorRangeEasyScoreCalculator; import ai.timefold.solver.core.testdomain.valuerange.sort.comparator.TestdataComparatorSortableEntityProvidingEntity; import ai.timefold.solver.core.testdomain.valuerange.sort.comparator.TestdataComparatorSortableEntityProvidingSolution; -import ai.timefold.solver.core.testdomain.valuerange.sort.comparatorstrength.OneValuePerEntityStrengthRangeEasyScoreCalculator; -import ai.timefold.solver.core.testdomain.valuerange.sort.comparatorstrength.TestdataStrengthSortableEntityProvidingEntity; -import ai.timefold.solver.core.testdomain.valuerange.sort.comparatorstrength.TestdataStrengthSortableEntityProvidingSolution; import ai.timefold.solver.core.testdomain.valuerange.sort.factory.OneValuePerEntityFactoryRangeEasyScoreCalculator; import ai.timefold.solver.core.testdomain.valuerange.sort.factory.TestdataFactorySortableEntityProvidingEntity; import ai.timefold.solver.core.testdomain.valuerange.sort.factory.TestdataFactorySortableEntityProvidingSolution; -import ai.timefold.solver.core.testdomain.valuerange.sort.factorystrength.OneValuePerEntityStrengthFactoryRangeEasyScoreCalculator; -import ai.timefold.solver.core.testdomain.valuerange.sort.factorystrength.TestdataStrengthFactorySortableEntityProvidingEntity; -import ai.timefold.solver.core.testdomain.valuerange.sort.factorystrength.TestdataStrengthFactorySortableEntityProvidingSolution; import ai.timefold.solver.core.testutil.PlannerTestUtils; import org.jspecify.annotations.NonNull; @@ -186,9 +162,9 @@ void solveWithPinnedEntities() { var v3 = new TestdataValue("v3"); solution.setValueList(Arrays.asList(v1, v2, v3)); solution.setEntityList(Arrays.asList( - new TestdataPinnedEntity("e1", null, false, false), - new TestdataPinnedEntity("e2", v2, true, false), - new TestdataPinnedEntity("e3", v3, false, true))); + new TestdataPinnedEntity("e1", null, false), + new TestdataPinnedEntity("e2", v2, false), + new TestdataPinnedEntity("e3", v3, true))); solution = PlannerTestUtils.solve(solverConfig, solution); assertThat(solution).isNotNull(); @@ -217,9 +193,9 @@ void solveWithPinnedEntitiesWhenUnassignedAllowedAndPinnedToNull() { var v3 = new TestdataValue("v3"); solution.setValueList(Arrays.asList(v1, v2, v3)); solution.setEntityList(Arrays.asList( - new TestdataPinnedAllowsUnassignedEntity("e1", null, false, false), - new TestdataPinnedAllowsUnassignedEntity("e2", v2, true, false), - new TestdataPinnedAllowsUnassignedEntity("e3", null, false, true))); + new TestdataPinnedAllowsUnassignedEntity("e1", null, false), + new TestdataPinnedAllowsUnassignedEntity("e2", v2, false), + new TestdataPinnedAllowsUnassignedEntity("e3", null, true))); solution = PlannerTestUtils.solve(solverConfig, solution, true); // No change will be made, but shadow variables will be updated. assertThat(solution).isNotNull(); @@ -238,9 +214,9 @@ void solveWithPinnedEntitiesWhenUnassignedNotAllowedAndPinnedToNull() { var v3 = new TestdataValue("v3"); solution.setValueList(Arrays.asList(v1, v2, v3)); solution.setEntityList(Arrays.asList( - new TestdataPinnedEntity("e1", null, false, false), - new TestdataPinnedEntity("e2", v2, true, false), - new TestdataPinnedEntity("e3", null, false, true))); + new TestdataPinnedEntity("e1", null, false), + new TestdataPinnedEntity("e2", v2, false), + new TestdataPinnedEntity("e3", null, true))); assertThatThrownBy(() -> PlannerTestUtils.solve(solverConfig, solution)) .hasMessageContaining("entity (e3)") @@ -705,111 +681,6 @@ private static List generateBasicVariableConfig return values; } - @ParameterizedTest - @MethodSource("generateBasicVariableConfiguration") - void solveStrengthBasicVariableQueueComparator(ConstructionHeuristicTestConfig phaseConfig) { - var solverConfig = PlannerTestUtils - .buildSolverConfig(TestdataDifficultySortableSolution.class, TestdataDifficultySortableEntity.class); - solverConfig.withEasyScoreCalculatorClass(OneValuePerEntityDifficultyEasyScoreCalculator.class); - solverConfig.withPhases(phaseConfig.config()); - - var solution = TestdataDifficultySortableSolution.generateSolution(3, 3, phaseConfig.shuffle()); - - solution = PlannerTestUtils.solve(solverConfig, solution); - assertThat(solution).isNotNull(); - if (phaseConfig.expected() != null) { - for (var i = 0; i < 3; i++) { - var id = "Generated Entity %d".formatted(i); - var entity = solution.getEntityList().stream() - .filter(e -> e.getCode().equals(id)) - .findFirst() - .orElseThrow(IllegalArgumentException::new); - assertThat(entity.getValue()).isNotNull(); - assertThat(entity.getValue().getComparatorValue()).isEqualTo(phaseConfig.expected[i]); - } - } - } - - @ParameterizedTest - @MethodSource("generateBasicVariableConfiguration") - void solveStrengthBasicVariableQueueFactory(ConstructionHeuristicTestConfig phaseConfig) { - var solverConfig = PlannerTestUtils - .buildSolverConfig(TestdataDifficultyFactorySortableSolution.class, - TestdataDifficultyFactorySortableEntity.class); - solverConfig.withEasyScoreCalculatorClass(OneValuePerEntityDifficultyFactoryEasyScoreCalculator.class); - solverConfig.withPhases(phaseConfig.config()); - - var solution = TestdataDifficultyFactorySortableSolution.generateSolution(3, 3, phaseConfig.shuffle()); - - solution = PlannerTestUtils.solve(solverConfig, solution); - assertThat(solution).isNotNull(); - if (phaseConfig.expected() != null) { - for (var i = 0; i < 3; i++) { - var id = "Generated Entity %d".formatted(i); - var entity = solution.getEntityList().stream() - .filter(e -> e.getCode().equals(id)) - .findFirst() - .orElseThrow(IllegalArgumentException::new); - assertThat(entity.getValue()).isNotNull(); - assertThat(entity.getValue().getComparatorValue()).isEqualTo(phaseConfig.expected[i]); - } - } - } - - @ParameterizedTest - @MethodSource("generateBasicVariableConfiguration") - void solveStrengthBasicVariableEntityRangeQueueComparator(ConstructionHeuristicTestConfig phaseConfig) { - var solverConfig = - PlannerTestUtils - .buildSolverConfig(TestdataStrengthSortableEntityProvidingSolution.class, - TestdataStrengthSortableEntityProvidingEntity.class) - .withEasyScoreCalculatorClass(OneValuePerEntityStrengthRangeEasyScoreCalculator.class) - .withPhases(phaseConfig.config()); - - var solution = TestdataStrengthSortableEntityProvidingSolution.generateSolution(3, 3, phaseConfig.shuffle()); - - solution = PlannerTestUtils.solve(solverConfig, solution); - assertThat(solution).isNotNull(); - if (phaseConfig.expected() != null) { - for (var i = 0; i < 3; i++) { - var id = "Generated Entity %d".formatted(i); - var entity = solution.getEntityList().stream() - .filter(e -> e.getCode().equals(id)) - .findFirst() - .orElseThrow(IllegalArgumentException::new); - assertThat(entity.getValue()).isNotNull(); - assertThat(entity.getValue().getComparatorValue()).isEqualTo(phaseConfig.expected[i]); - } - } - } - - @ParameterizedTest - @MethodSource("generateBasicVariableConfiguration") - void solveStrengthBasicVariableEntityRangeQueueFactory(ConstructionHeuristicTestConfig phaseConfig) { - var solverConfig = - PlannerTestUtils - .buildSolverConfig(TestdataStrengthFactorySortableEntityProvidingSolution.class, - TestdataStrengthFactorySortableEntityProvidingEntity.class) - .withEasyScoreCalculatorClass(OneValuePerEntityStrengthFactoryRangeEasyScoreCalculator.class) - .withPhases(phaseConfig.config()); - - var solution = TestdataStrengthFactorySortableEntityProvidingSolution.generateSolution(3, 3, phaseConfig.shuffle()); - - solution = PlannerTestUtils.solve(solverConfig, solution); - assertThat(solution).isNotNull(); - if (phaseConfig.expected() != null) { - for (var i = 0; i < 3; i++) { - var id = "Generated Entity %d".formatted(i); - var entity = solution.getEntityList().stream() - .filter(e -> e.getCode().equals(id)) - .findFirst() - .orElseThrow(IllegalArgumentException::new); - assertThat(entity.getValue()).isNotNull(); - assertThat(entity.getValue().getComparatorValue()).isEqualTo(phaseConfig.expected[i]); - } - } - } - @ParameterizedTest @MethodSource("generateBasicVariableConfiguration") void solveBasicVariableQueueComparator(ConstructionHeuristicTestConfig phaseConfig) { @@ -1527,107 +1398,6 @@ void failConstructionHeuristicListMixedProperties() { "comparatorFactoryClass (ai.timefold.solver.core.testdomain.common.DummyValueFactory) at the same time."); } - @Test - void failConstructionHeuristicMixedProperties() { - // Strength and Factory properties - var solverConfig = - PlannerTestUtils - .buildSolverConfig(TestdataInvalidMixedStrengthSortableSolution.class, - TestdataInvalidMixedStrengthSortableEntity.class) - .withEasyScoreCalculatorClass(DummyHardSoftEasyScoreCalculator.class); - var solution = new TestdataInvalidMixedStrengthSortableSolution(); - assertThatCode(() -> PlannerTestUtils.solve(solverConfig, solution)) - .hasMessageContaining( - "The entityClass (class ai.timefold.solver.core.testdomain.sort.invalid.mixed.strength.TestdataInvalidMixedStrengthSortableEntity) property (value)") - .hasMessageContaining( - "cannot have a strengthComparatorClass (ai.timefold.solver.core.testdomain.common.DummyValueComparator)") - .hasMessageContaining( - "strengthWeightFactoryClass (ai.timefold.solver.core.testdomain.common.DummyWeightValueFactory) at the same time."); - - // Comparator and Factory properties - var otherSolverConfig = - PlannerTestUtils - .buildSolverConfig(TestdataInvalidMixedComparatorSortableSolution.class, - TestdataInvalidMixedComparatorSortableEntity.class) - .withEasyScoreCalculatorClass(DummyHardSoftEasyScoreCalculator.class); - var otherSolution = new TestdataInvalidMixedComparatorSortableSolution(); - assertThatCode(() -> PlannerTestUtils.solve(otherSolverConfig, otherSolution)) - .hasMessageContaining( - "The entityClass (class ai.timefold.solver.core.testdomain.sort.invalid.mixed.comparator.TestdataInvalidMixedComparatorSortableEntity) property (value)") - .hasMessageContaining( - "cannot have a comparatorClass (ai.timefold.solver.core.testdomain.common.DummyValueComparator)") - .hasMessageContaining( - "comparatorFactoryClass (ai.timefold.solver.core.testdomain.common.DummyValueFactory) at the same time."); - } - - @Test - void failConstructionHeuristicBothProperties() { - // Value - { - // Two comparator properties - var solverConfig = - PlannerTestUtils - .buildSolverConfig(TestdataInvalidTwoValueComparatorSortableSolution.class, - TestdataInvalidTwoValueComparatorSortableEntity.class) - .withEasyScoreCalculatorClass(DummyHardSoftEasyScoreCalculator.class); - var solution = new TestdataInvalidTwoValueComparatorSortableSolution(); - assertThatCode(() -> PlannerTestUtils.solve(solverConfig, solution)) - .hasMessageContaining( - "The entityClass (class ai.timefold.solver.core.testdomain.sort.invalid.twocomparator.value.TestdataInvalidTwoValueComparatorSortableEntity) property (value)") - .hasMessageContaining( - "cannot have a strengthComparatorClass (ai.timefold.solver.core.testdomain.common.DummyValueComparator)") - .hasMessageContaining( - "and a comparatorClass (ai.timefold.solver.core.testdomain.common.DummyValueComparator) at the same time."); - - // Comparator and Factory properties - var otherSolverConfig = - PlannerTestUtils - .buildSolverConfig(TestdataInvalidTwoValueFactorySortableSolution.class, - TestdataInvalidTwoValueFactorySortableEntity.class) - .withEasyScoreCalculatorClass(DummyHardSoftEasyScoreCalculator.class); - var otherSolution = new TestdataInvalidTwoValueFactorySortableSolution(); - assertThatCode(() -> PlannerTestUtils.solve(otherSolverConfig, otherSolution)) - .hasMessageContaining( - "The entityClass (class ai.timefold.solver.core.testdomain.sort.invalid.twofactory.value.TestdataInvalidTwoValueFactorySortableEntity) property (value)") - .hasMessageContaining( - "cannot have a strengthWeightFactoryClass (ai.timefold.solver.core.testdomain.common.DummyWeightValueFactory)") - .hasMessageContaining( - "comparatorFactoryClass (ai.timefold.solver.core.testdomain.common.DummyValueFactory) at the same time."); - } - // Entity - { - // Two comparator properties - var solverConfig = - PlannerTestUtils - .buildSolverConfig(TestdataInvalidTwoEntityComparatorSortableSolution.class, - TestdataInvalidTwoEntityComparatorSortableEntity.class) - .withEasyScoreCalculatorClass(DummyHardSoftEasyScoreCalculator.class); - var solution = new TestdataInvalidTwoEntityComparatorSortableSolution(); - assertThatCode(() -> PlannerTestUtils.solve(solverConfig, solution)) - .hasMessageContaining( - "The entityClass (class ai.timefold.solver.core.testdomain.sort.invalid.twocomparator.entity.TestdataInvalidTwoEntityComparatorSortableEntity)") - .hasMessageContaining( - "cannot have a difficultyComparatorClass (ai.timefold.solver.core.testdomain.common.DummyValueComparator)") - .hasMessageContaining( - "and a comparatorClass (ai.timefold.solver.core.testdomain.common.DummyValueComparator) at the same time."); - - // Comparator and Factory properties - var otherSolverConfig = - PlannerTestUtils - .buildSolverConfig(TestdataInvalidTwoEntityFactorySortableSolution.class, - TestdataInvalidTwoEntityFactorySortableEntity.class) - .withEasyScoreCalculatorClass(DummyHardSoftEasyScoreCalculator.class); - var otherSolution = new TestdataInvalidTwoEntityFactorySortableSolution(); - assertThatCode(() -> PlannerTestUtils.solve(otherSolverConfig, otherSolution)) - .hasMessageContaining( - "The entityClass (class ai.timefold.solver.core.testdomain.sort.invalid.twofactory.entity.TestdataInvalidTwoEntityFactorySortableEntity)") - .hasMessageContaining( - "cannot have a difficultyWeightFactoryClass (ai.timefold.solver.core.testdomain.common.DummyValueFactory)") - .hasMessageContaining( - "comparatorFactoryClass (ai.timefold.solver.core.testdomain.common.DummyValueFactory) at the same time."); - } - } - @Test void failConstructionHeuristicBothNearbyAndSorting() { // Two comparator properties @@ -1712,7 +1482,8 @@ public static class TestdataSolutionEasyScoreCalculator } } - private record ConstructionHeuristicTestConfig(ConstructionHeuristicPhaseConfig config, int[] expected, boolean shuffle) { + private record ConstructionHeuristicTestConfig(ConstructionHeuristicPhaseConfig config, int[] expected, + boolean shuffle) { } } diff --git a/core/src/test/java/ai/timefold/solver/core/impl/constructionheuristic/placer/entity/QueuedEntityPlacerFactoryTest.java b/core/src/test/java/ai/timefold/solver/core/impl/constructionheuristic/placer/entity/QueuedEntityPlacerFactoryTest.java index 6c8ea1d6e2f..eab64879bc0 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/constructionheuristic/placer/entity/QueuedEntityPlacerFactoryTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/constructionheuristic/placer/entity/QueuedEntityPlacerFactoryTest.java @@ -27,9 +27,9 @@ import ai.timefold.solver.core.impl.score.director.ValueRangeManager; import ai.timefold.solver.core.impl.solver.scope.SolverScope; import ai.timefold.solver.core.testdomain.TestdataValue; -import ai.timefold.solver.core.testdomain.difficultyweight.TestdataDifficultyWeightSolution; import ai.timefold.solver.core.testdomain.multivar.TestdataMultiVarEntity; import ai.timefold.solver.core.testdomain.multivar.TestdataMultiVarSolution; +import ai.timefold.solver.core.testdomain.sort.comparator.TestdataComparatorSortableSolution; import org.junit.jupiter.api.Test; @@ -85,12 +85,12 @@ void buildFromUnfoldNew() { void buildWithEntitySortManner() { ChangeMoveSelectorConfig primaryMoveSelectorConfig = new ChangeMoveSelectorConfig() .withValueSelectorConfig(new ValueSelectorConfig("primaryValue")); - var configPolicy = buildHeuristicConfigPolicy(TestdataDifficultyWeightSolution.buildSolutionDescriptor(), + var configPolicy = buildHeuristicConfigPolicy(TestdataComparatorSortableSolution.buildSolutionDescriptor(), EntitySorterManner.DESCENDING_IF_AVAILABLE); QueuedEntityPlacerConfig placerConfig = QueuedEntityPlacerFactory.unfoldNew(configPolicy, List.of(primaryMoveSelectorConfig)); var entityPlacer = - new QueuedEntityPlacerFactory(placerConfig); + new QueuedEntityPlacerFactory(placerConfig); var entitySelectorConfig = entityPlacer.buildEntitySelectorConfig(configPolicy); assertThat(entitySelectorConfig.getSelectionOrder()).isEqualTo(SelectionOrder.SORTED); assertThat(entitySelectorConfig.getSorterManner()).isEqualTo(EntitySorterManner.DESCENDING_IF_AVAILABLE); diff --git a/core/src/test/java/ai/timefold/solver/core/impl/domain/common/accessor/gizmo/GizmoMemberAccessorImplementorTest.java b/core/src/test/java/ai/timefold/solver/core/impl/domain/common/accessor/gizmo/GizmoMemberAccessorImplementorTest.java index 6505229e03d..c8119065099 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/domain/common/accessor/gizmo/GizmoMemberAccessorImplementorTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/domain/common/accessor/gizmo/GizmoMemberAccessorImplementorTest.java @@ -6,8 +6,8 @@ import java.lang.reflect.Method; import java.util.List; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningPin; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.valuerange.ValueRangeProvider; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; import ai.timefold.solver.core.testdomain.TestdataEntity; diff --git a/core/src/test/java/ai/timefold/solver/core/impl/domain/entity/descriptor/EntityDescriptorTest.java b/core/src/test/java/ai/timefold/solver/core/impl/domain/entity/descriptor/EntityDescriptorTest.java index 36a8b86fce1..00b718badcc 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/domain/entity/descriptor/EntityDescriptorTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/domain/entity/descriptor/EntityDescriptorTest.java @@ -7,58 +7,14 @@ import ai.timefold.solver.core.testdomain.TestdataEntity; import ai.timefold.solver.core.testdomain.immutable.TestdataSolution; -import ai.timefold.solver.core.testdomain.inheritance.entity.single.baseannotated.classes.pinned.TestdataExtendedPinnedEntity; -import ai.timefold.solver.core.testdomain.inheritance.entity.single.baseannotated.classes.pinned.TestdataExtendedPinnedSolution; import ai.timefold.solver.core.testdomain.inheritance.solution.baseannotated.childtoo.TestdataBothAnnotatedChildEntity; import ai.timefold.solver.core.testdomain.inheritance.solution.baseannotated.childtoo.TestdataBothAnnotatedExtendedSolution; import ai.timefold.solver.core.testdomain.invalid.noplanningvar.TestdataNoVariableSolution; -import ai.timefold.solver.core.testdomain.pinned.TestdataPinnedEntity; import org.junit.jupiter.api.Test; class EntityDescriptorTest { - @Test - void movableEntitySelectionFilter() { - var entityDescriptor = TestdataPinnedEntity.buildEntityDescriptor(); - assertThat(entityDescriptor.hasEffectiveMovableEntityFilter()).isTrue(); - var movableEntityFilter = - entityDescriptor.getEffectiveMovableEntityFilter(); - assertThat(movableEntityFilter).isNotNull(); - - assertThat(movableEntityFilter.test(null, - new TestdataPinnedEntity("e1", null, false, false))).isTrue(); - assertThat(movableEntityFilter.test(null, - new TestdataPinnedEntity("e2", null, true, false))).isFalse(); - } - - @Test - void extendedMovableEntitySelectionFilterUsedByChildSelector() { - var solutionDescriptor = - TestdataExtendedPinnedSolution.buildSolutionDescriptor(); - - var childEntityDescriptor = - solutionDescriptor.findEntityDescriptor(TestdataExtendedPinnedEntity.class); - assertThat(childEntityDescriptor.hasEffectiveMovableEntityFilter()).isTrue(); - var childMovableEntityFilter = - childEntityDescriptor.getEffectiveMovableEntityFilter(); - assertThat(childMovableEntityFilter).isNotNull(); - - // No new TestdataPinnedEntity() because a child selector would never select a pure parent instance - assertThat(childMovableEntityFilter.test(null, - new TestdataExtendedPinnedEntity("e3", null, false, false, null, false, false))).isTrue(); - assertThat(childMovableEntityFilter.test(null, - new TestdataExtendedPinnedEntity("e4", null, true, false, null, false, false))).isFalse(); - assertThat(childMovableEntityFilter.test(null, - new TestdataExtendedPinnedEntity("e5", null, false, true, null, false, false))).isFalse(); - assertThat(childMovableEntityFilter.test(null, - new TestdataExtendedPinnedEntity("e6", null, false, false, null, true, false))).isFalse(); - assertThat(childMovableEntityFilter.test(null, - new TestdataExtendedPinnedEntity("e7", null, false, false, null, false, true))).isFalse(); - assertThat(childMovableEntityFilter.test(null, - new TestdataExtendedPinnedEntity("e8", null, true, true, null, true, true))).isFalse(); - } - @Test void extractExtendedEntities() { var solution = new TestdataBothAnnotatedExtendedSolution("s1"); diff --git a/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/AbstractLookupTest.java b/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/AbstractLookupTest.java index 0d464dc46ea..3642a800975 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/AbstractLookupTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/AbstractLookupTest.java @@ -1,7 +1,6 @@ package ai.timefold.solver.core.impl.domain.lookup; import ai.timefold.solver.core.api.domain.common.DomainAccessType; -import ai.timefold.solver.core.api.domain.lookup.LookUpStrategyType; import ai.timefold.solver.core.impl.domain.common.accessor.MemberAccessorFactory; import ai.timefold.solver.core.impl.domain.policy.DescriptorPolicy; diff --git a/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpManagerTest.java b/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpManagerTest.java index f626c9efdc1..31e47c8f22f 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpManagerTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpManagerTest.java @@ -4,7 +4,6 @@ import java.util.Arrays; -import ai.timefold.solver.core.api.domain.lookup.LookUpStrategyType; import ai.timefold.solver.core.testdomain.clone.lookup.TestdataObjectIntegerId; import ai.timefold.solver.core.testdomain.interfaces.TestdataInterfaceEntity; import ai.timefold.solver.core.testdomain.interfaces.TestdataInterfaceValue; diff --git a/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyEqualityTest.java b/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyEqualityTest.java deleted file mode 100644 index a9894bac07c..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyEqualityTest.java +++ /dev/null @@ -1,101 +0,0 @@ -package ai.timefold.solver.core.impl.domain.lookup; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import static org.assertj.core.api.Assertions.assertThatIllegalStateException; - -import ai.timefold.solver.core.api.domain.lookup.LookUpStrategyType; -import ai.timefold.solver.core.testdomain.clone.lookup.TestdataObjectEquals; -import ai.timefold.solver.core.testdomain.clone.lookup.TestdataObjectEqualsNoHashCode; -import ai.timefold.solver.core.testdomain.clone.lookup.TestdataObjectEqualsSubclass; -import ai.timefold.solver.core.testdomain.clone.lookup.TestdataObjectNoId; - -import org.junit.jupiter.api.Test; - -class LookUpStrategyEqualityTest extends AbstractLookupTest { - - public LookUpStrategyEqualityTest() { - super(LookUpStrategyType.EQUALITY); - } - - @Test - void addRemoveWithEquals() { - TestdataObjectEquals object = new TestdataObjectEquals(0); - lookUpManager.addWorkingObject(object); - lookUpManager.removeWorkingObject(object); - // The removed object cannot be looked up - assertThat(lookUpManager.lookUpWorkingObjectOrReturnNull(object)).isNull(); - } - - @Test - void addWithEqualsInSuperclass() { - TestdataObjectEqualsSubclass object = new TestdataObjectEqualsSubclass(0); - lookUpManager.addWorkingObject(object); - assertThat(lookUpManager.lookUpWorkingObject(object)).isSameAs(object); - } - - @Test - void addWithoutEquals() { - TestdataObjectNoId object = new TestdataObjectNoId(); - assertThatIllegalArgumentException() - .isThrownBy(() -> lookUpManager.addWorkingObject(object)) - .withMessageContaining("override the equals() method") - .withMessageContaining(TestdataObjectNoId.class.getSimpleName()); - } - - @Test - void addWithoutHashCode() { - TestdataObjectEqualsNoHashCode object = new TestdataObjectEqualsNoHashCode(0); - assertThatIllegalArgumentException() - .isThrownBy(() -> lookUpManager.addWorkingObject(object)) - .withMessageContaining("overrides the hashCode() method") - .withMessageContaining(TestdataObjectEqualsNoHashCode.class.getSimpleName()); - } - - @Test - void removeWithoutEquals() { - TestdataObjectNoId object = new TestdataObjectNoId(); - assertThatIllegalArgumentException() - .isThrownBy(() -> lookUpManager.removeWorkingObject(object)) - .withMessageContaining("override the equals() method") - .withMessageContaining(TestdataObjectNoId.class.getSimpleName()); - } - - @Test - void addEqualObjects() { - TestdataObjectEquals object = new TestdataObjectEquals(2); - lookUpManager.addWorkingObject(object); - assertThatIllegalStateException() - .isThrownBy(() -> lookUpManager.addWorkingObject(new TestdataObjectEquals(2))) - .withMessageContaining(object.toString()); - } - - @Test - void removeWithoutAdding() { - TestdataObjectEquals object = new TestdataObjectEquals(0); - assertThatIllegalStateException() - .isThrownBy(() -> lookUpManager.removeWorkingObject(object)) - .withMessageContaining("differ"); - } - - @Test - void lookUpWithEquals() { - TestdataObjectEquals object = new TestdataObjectEquals(1); - lookUpManager.addWorkingObject(object); - assertThat(lookUpManager.lookUpWorkingObject(new TestdataObjectEquals(1))).isSameAs(object); - } - - @Test - void lookUpWithoutEquals() { - TestdataObjectNoId object = new TestdataObjectNoId(); - assertThatIllegalArgumentException() - .isThrownBy(() -> lookUpManager.lookUpWorkingObject(object)) - .withMessageContaining("override the equals() method"); - } - - @Test - void lookUpWithoutAdding() { - TestdataObjectEquals object = new TestdataObjectEquals(0); - assertThat(lookUpManager.lookUpWorkingObjectOrReturnNull(object)).isNull(); - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyIdOrFailTest.java b/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyIdOrFailTest.java index 486257fb491..5376b9edce3 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyIdOrFailTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyIdOrFailTest.java @@ -4,8 +4,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; -import ai.timefold.solver.core.api.domain.lookup.LookUpStrategyType; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.testdomain.clone.lookup.TestdataObjectEnum; import ai.timefold.solver.core.testdomain.clone.lookup.TestdataObjectIntegerId; import ai.timefold.solver.core.testdomain.clone.lookup.TestdataObjectMultipleIds; diff --git a/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyIdOrNoneTest.java b/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyIdOrNoneTest.java index 9830c399174..5d4ebf027ab 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyIdOrNoneTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyIdOrNoneTest.java @@ -4,8 +4,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalStateException; -import ai.timefold.solver.core.api.domain.lookup.LookUpStrategyType; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.testdomain.clone.lookup.TestdataObjectIntegerId; import ai.timefold.solver.core.testdomain.clone.lookup.TestdataObjectIntegerIdSubclass; import ai.timefold.solver.core.testdomain.clone.lookup.TestdataObjectMultipleIds; diff --git a/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyImmutableTest.java b/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyImmutableTest.java index 447373ff6a4..46e12b0c4e1 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyImmutableTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyImmutableTest.java @@ -23,8 +23,6 @@ import java.time.temporal.ChronoUnit; import java.util.stream.Stream; -import ai.timefold.solver.core.api.domain.lookup.LookUpStrategyType; - import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; diff --git a/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyNoneTest.java b/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyNoneTest.java index 6c7289af8d8..6841ddf13f5 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyNoneTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/domain/lookup/LookUpStrategyNoneTest.java @@ -2,7 +2,6 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -import ai.timefold.solver.core.api.domain.lookup.LookUpStrategyType; import ai.timefold.solver.core.testdomain.clone.lookup.TestdataObjectIntegerId; import ai.timefold.solver.core.testdomain.clone.lookup.TestdataObjectMultipleIds; import ai.timefold.solver.core.testdomain.clone.lookup.TestdataObjectNoId; diff --git a/core/src/test/java/ai/timefold/solver/core/impl/exhaustivesearch/DefaultExhaustiveSearchPhaseTest.java b/core/src/test/java/ai/timefold/solver/core/impl/exhaustivesearch/DefaultExhaustiveSearchPhaseTest.java index edb10b9d5f2..e3e252711ac 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/exhaustivesearch/DefaultExhaustiveSearchPhaseTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/exhaustivesearch/DefaultExhaustiveSearchPhaseTest.java @@ -256,9 +256,9 @@ void solveBasicWithPinnedEntities() { var v3 = new TestdataValue("v3"); solution.setValueList(Arrays.asList(v1, v2, v3)); solution.setEntityList(Arrays.asList( - new TestdataPinnedEntity("e1", null, false, false), - new TestdataPinnedEntity("e2", v2, true, false), - new TestdataPinnedEntity("e3", v3, false, true))); + new TestdataPinnedEntity("e1", null, false), + new TestdataPinnedEntity("e2", v2, false), + new TestdataPinnedEntity("e3", v3, true))); solution = PlannerTestUtils.solve(solverConfig, solution); assertThat(solution).isNotNull(); @@ -339,9 +339,9 @@ void solveWithPinnedEntitiesWhenUnassignedAllowedAndPinnedToNull() { var v3 = new TestdataValue("v3"); solution.setValueList(Arrays.asList(v1, v2, v3)); solution.setEntityList(Arrays.asList( - new TestdataPinnedAllowsUnassignedEntity("e1", null, false, false), - new TestdataPinnedAllowsUnassignedEntity("e2", v2, true, false), - new TestdataPinnedAllowsUnassignedEntity("e3", null, false, true))); + new TestdataPinnedAllowsUnassignedEntity("e1", null, false), + new TestdataPinnedAllowsUnassignedEntity("e2", v2, false), + new TestdataPinnedAllowsUnassignedEntity("e3", null, true))); solution = PlannerTestUtils.solve(solverConfig, solution, true); // No change will be made, but shadows will be updated. assertThat(solution).isNotNull(); @@ -359,9 +359,9 @@ void solveWithPinnedEntitiesWhenUnassignedNotAllowedAndPinnedToNull() { var v3 = new TestdataValue("v3"); solution.setValueList(Arrays.asList(v1, v2, v3)); solution.setEntityList(Arrays.asList( - new TestdataPinnedEntity("e1", null, false, false), - new TestdataPinnedEntity("e2", v2, true, false), - new TestdataPinnedEntity("e3", null, false, true))); + new TestdataPinnedEntity("e1", null, false), + new TestdataPinnedEntity("e2", v2, false), + new TestdataPinnedEntity("e3", null, true))); assertThatThrownBy(() -> PlannerTestUtils.solve(solverConfig, solution)) .hasMessageContaining("entity (e3)") diff --git a/core/src/test/java/ai/timefold/solver/core/impl/localsearch/DefaultLocalSearchPhaseTest.java b/core/src/test/java/ai/timefold/solver/core/impl/localsearch/DefaultLocalSearchPhaseTest.java index eb18c07e723..97c4a05c109 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/localsearch/DefaultLocalSearchPhaseTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/localsearch/DefaultLocalSearchPhaseTest.java @@ -73,18 +73,12 @@ void solveWithPinnedEntities() { var v3 = new TestdataValue("v3"); solution.setValueList(Arrays.asList(v1, v2, v3)); solution.setEntityList(Arrays.asList( - new TestdataPinnedEntity("e1", v1, false, false), - new TestdataPinnedEntity("e2", v2, true, false), - new TestdataPinnedEntity("e3", v3, false, true))); + new TestdataPinnedEntity("e1", v1, false), + new TestdataPinnedEntity("e2", v2, false), + new TestdataPinnedEntity("e3", v3, true))); solution = PlannerTestUtils.solve(solverConfig, solution, true); // TODO incentive it to change something assertThat(solution).isNotNull(); - var solvedE1 = solution.getEntityList().get(0); - assertCode("e1", solvedE1); - assertThat(solvedE1.getValue()).isNotNull(); - var solvedE2 = solution.getEntityList().get(1); - assertCode("e2", solvedE2); - assertThat(solvedE2.getValue()).isEqualTo(v2); var solvedE3 = solution.getEntityList().get(2); assertCode("e3", solvedE3); assertThat(solvedE3.getValue()).isEqualTo(v3); @@ -103,9 +97,9 @@ void solveWithPinnedEntitiesWhenUnassignedAllowedAndPinnedToNull() { var v3 = new TestdataValue("v3"); solution.setValueList(Arrays.asList(v1, v2, v3)); solution.setEntityList(Arrays.asList( - new TestdataPinnedAllowsUnassignedEntity("e1", null, false, false), - new TestdataPinnedAllowsUnassignedEntity("e2", v2, true, false), - new TestdataPinnedAllowsUnassignedEntity("e3", null, false, true))); + new TestdataPinnedAllowsUnassignedEntity("e1", null, false), + new TestdataPinnedAllowsUnassignedEntity("e2", v2, false), + new TestdataPinnedAllowsUnassignedEntity("e3", null, true))); solution = PlannerTestUtils.solve(solverConfig, solution, true); // No change will be made. assertThat(solution).isNotNull(); @@ -124,9 +118,9 @@ void solveWithPinnedEntitiesWhenUnassignedNotAllowedAndPinnedToNull() { var v3 = new TestdataValue("v3"); solution.setValueList(Arrays.asList(v1, v2, v3)); solution.setEntityList(Arrays.asList( - new TestdataPinnedEntity("e1", null, false, false), - new TestdataPinnedEntity("e2", v2, true, false), - new TestdataPinnedEntity("e3", null, false, true))); + new TestdataPinnedEntity("e1", null, false), + new TestdataPinnedEntity("e2", v2, false), + new TestdataPinnedEntity("e3", null, true))); assertThatThrownBy(() -> PlannerTestUtils.solve(solverConfig, solution)) .hasMessageContaining("entity (e3)") @@ -197,18 +191,12 @@ void solveTabuSearchWithPinnedEntities() { var v3 = new TestdataValue("v3"); solution.setValueList(Arrays.asList(v1, v2, v3)); solution.setEntityList(Arrays.asList( - new TestdataPinnedEntity("e1", v1, false, false), - new TestdataPinnedEntity("e2", v2, true, false), - new TestdataPinnedEntity("e3", v3, false, true))); + new TestdataPinnedEntity("e1", v1, false), + new TestdataPinnedEntity("e2", v2, false), + new TestdataPinnedEntity("e3", v3, true))); solution = PlannerTestUtils.solve(solverConfig, solution, true); // TODO incentive it to change something assertThat(solution).isNotNull(); - var solvedE1 = solution.getEntityList().get(0); - assertCode("e1", solvedE1); - assertThat(solvedE1.getValue()).isNotNull(); - var solvedE2 = solution.getEntityList().get(1); - assertCode("e2", solvedE2); - assertThat(solvedE2.getValue()).isEqualTo(v2); var solvedE3 = solution.getEntityList().get(2); assertCode("e3", solvedE3); assertThat(solvedE3.getValue()).isEqualTo(v3); diff --git a/core/src/test/java/ai/timefold/solver/core/impl/solver/DefaultSolverTest.java b/core/src/test/java/ai/timefold/solver/core/impl/solver/DefaultSolverTest.java index c8b068d37e8..7c79acbfe64 100644 --- a/core/src/test/java/ai/timefold/solver/core/impl/solver/DefaultSolverTest.java +++ b/core/src/test/java/ai/timefold/solver/core/impl/solver/DefaultSolverTest.java @@ -495,8 +495,8 @@ void solvePinnedEntityList() { var v1 = new TestdataValue("v1"); var v2 = new TestdataValue("v2"); solution.setValueList(Arrays.asList(v1, v2)); - solution.setEntityList(Arrays.asList(new TestdataPinnedEntity("e1", v1, true, false), - new TestdataPinnedEntity("e2", v2, false, true))); + solution.setEntityList(Arrays.asList(new TestdataPinnedEntity("e1", v1, true), + new TestdataPinnedEntity("e2", v2, true))); solution = PlannerTestUtils.solve(solverConfig, solution, true); assertThat(solution).isNotNull(); diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/TestdataObject.java b/core/src/test/java/ai/timefold/solver/core/testdomain/TestdataObject.java index 754e53cb217..4b65307f67c 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/TestdataObject.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/TestdataObject.java @@ -1,6 +1,6 @@ package ai.timefold.solver.core.testdomain; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.testutil.CodeAssertable; public class TestdataObject implements CodeAssertable { diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/clone/lookup/TestdataObjectIntegerId.java b/core/src/test/java/ai/timefold/solver/core/testdomain/clone/lookup/TestdataObjectIntegerId.java index fc9ccbf60e8..2a7a8fe0788 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/clone/lookup/TestdataObjectIntegerId.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/clone/lookup/TestdataObjectIntegerId.java @@ -1,6 +1,6 @@ package ai.timefold.solver.core.testdomain.clone.lookup; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; public class TestdataObjectIntegerId { diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/clone/lookup/TestdataObjectMultipleIds.java b/core/src/test/java/ai/timefold/solver/core/testdomain/clone/lookup/TestdataObjectMultipleIds.java index 1f9f132cb06..e84e03278b7 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/clone/lookup/TestdataObjectMultipleIds.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/clone/lookup/TestdataObjectMultipleIds.java @@ -1,6 +1,6 @@ package ai.timefold.solver.core.testdomain.clone.lookup; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; public class TestdataObjectMultipleIds { diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/clone/lookup/TestdataObjectPrimitiveIntId.java b/core/src/test/java/ai/timefold/solver/core/testdomain/clone/lookup/TestdataObjectPrimitiveIntId.java index 4b47a642736..204f9696df8 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/clone/lookup/TestdataObjectPrimitiveIntId.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/clone/lookup/TestdataObjectPrimitiveIntId.java @@ -1,6 +1,6 @@ package ai.timefold.solver.core.testdomain.clone.lookup; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; public class TestdataObjectPrimitiveIntId { diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/comparable/TestdataDifficultyComparingEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/comparable/TestdataDifficultyComparingEntity.java index a6a664a4c95..3a89cd1d5d7 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/comparable/TestdataDifficultyComparingEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/comparable/TestdataDifficultyComparingEntity.java @@ -7,7 +7,7 @@ import ai.timefold.solver.core.testdomain.TestdataObject; import ai.timefold.solver.core.testdomain.TestdataValue; -@PlanningEntity(difficultyComparatorClass = TestdataCodeComparator.class) +@PlanningEntity(comparatorClass = TestdataCodeComparator.class) public class TestdataDifficultyComparingEntity extends TestdataObject { public static EntityDescriptor buildEntityDescriptor() { @@ -33,7 +33,7 @@ public TestdataDifficultyComparingEntity(String code, TestdataValue value) { this.value = value; } - @PlanningVariable(valueRangeProviderRefs = { "valueRange" }, strengthComparatorClass = TestdataCodeComparator.class) + @PlanningVariable(valueRangeProviderRefs = { "valueRange" }, comparatorClass = TestdataCodeComparator.class) public TestdataValue getValue() { return value; } diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/difficultyweight/TestdataDifficultyFactory.java b/core/src/test/java/ai/timefold/solver/core/testdomain/difficultyweight/TestdataDifficultyFactory.java deleted file mode 100644 index c76995fd7fd..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/difficultyweight/TestdataDifficultyFactory.java +++ /dev/null @@ -1,13 +0,0 @@ -package ai.timefold.solver.core.testdomain.difficultyweight; - -import ai.timefold.solver.core.impl.heuristic.selector.common.decorator.SelectionSorterWeightFactory; - -public class TestdataDifficultyFactory - implements SelectionSorterWeightFactory { - - @Override - public Comparable createSorterWeight(TestdataDifficultyWeightSolution testdataDifficultyWeightSolution, - TestdataDifficultyWeightEntity selection) { - return 0; - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/difficultyweight/TestdataDifficultyWeightEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/difficultyweight/TestdataDifficultyWeightEntity.java deleted file mode 100644 index 802bb2a0d09..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/difficultyweight/TestdataDifficultyWeightEntity.java +++ /dev/null @@ -1,40 +0,0 @@ -package ai.timefold.solver.core.testdomain.difficultyweight; - -import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.variable.PlanningVariable; -import ai.timefold.solver.core.impl.domain.entity.descriptor.EntityDescriptor; -import ai.timefold.solver.core.impl.domain.variable.descriptor.GenuineVariableDescriptor; -import ai.timefold.solver.core.testdomain.TestdataObject; - -@PlanningEntity(difficultyWeightFactoryClass = TestdataDifficultyFactory.class) -public class TestdataDifficultyWeightEntity extends TestdataObject { - - public static EntityDescriptor buildEntityDescriptor() { - return TestdataDifficultyWeightSolution.buildSolutionDescriptor() - .findEntityDescriptorOrFail(TestdataDifficultyWeightEntity.class); - } - - public static GenuineVariableDescriptor buildVariableDescriptorForValue() { - return buildEntityDescriptor().getGenuineVariableDescriptor("value"); - } - - private TestdataDifficultyWeightValue value; - - public TestdataDifficultyWeightEntity(String code) { - super(code); - } - - public TestdataDifficultyWeightEntity(String code, TestdataDifficultyWeightValue value) { - this(code); - this.value = value; - } - - @PlanningVariable(valueRangeProviderRefs = "valueRange") - public TestdataDifficultyWeightValue getValue() { - return value; - } - - public void setValue(TestdataDifficultyWeightValue value) { - this.value = value; - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/difficultyweight/TestdataDifficultyWeightSolution.java b/core/src/test/java/ai/timefold/solver/core/testdomain/difficultyweight/TestdataDifficultyWeightSolution.java deleted file mode 100644 index c1e64c3bfbc..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/difficultyweight/TestdataDifficultyWeightSolution.java +++ /dev/null @@ -1,82 +0,0 @@ -package ai.timefold.solver.core.testdomain.difficultyweight; - -import java.util.ArrayList; -import java.util.List; - -import ai.timefold.solver.core.api.domain.solution.PlanningEntityCollectionProperty; -import ai.timefold.solver.core.api.domain.solution.PlanningScore; -import ai.timefold.solver.core.api.domain.solution.PlanningSolution; -import ai.timefold.solver.core.api.domain.solution.ProblemFactCollectionProperty; -import ai.timefold.solver.core.api.domain.valuerange.ValueRangeProvider; -import ai.timefold.solver.core.api.score.SimpleScore; -import ai.timefold.solver.core.impl.domain.solution.descriptor.SolutionDescriptor; -import ai.timefold.solver.core.testdomain.TestdataObject; - -@PlanningSolution -public class TestdataDifficultyWeightSolution extends TestdataObject { - - public static SolutionDescriptor buildSolutionDescriptor() { - return SolutionDescriptor.buildSolutionDescriptor(TestdataDifficultyWeightSolution.class, - TestdataDifficultyWeightEntity.class); - } - - public static TestdataDifficultyWeightSolution generateSolution() { - return generateSolution(5, 7); - } - - public static TestdataDifficultyWeightSolution generateSolution(int valueListSize, int entityListSize) { - TestdataDifficultyWeightSolution solution = new TestdataDifficultyWeightSolution("Generated Solution 0"); - List valueList = new ArrayList<>(valueListSize); - for (int i = 0; i < valueListSize; i++) { - TestdataDifficultyWeightValue value = new TestdataDifficultyWeightValue("Generated Value " + i); - valueList.add(value); - } - solution.setValueList(valueList); - List entityList = new ArrayList<>(entityListSize); - for (int i = 0; i < entityListSize; i++) { - TestdataDifficultyWeightValue value = valueList.get(i % valueListSize); - TestdataDifficultyWeightEntity entity = new TestdataDifficultyWeightEntity("Generated Entity " + i, value); - entityList.add(entity); - } - solution.setEntityList(entityList); - return solution; - } - - private List valueList; - private List entityList; - - private SimpleScore score; - - public TestdataDifficultyWeightSolution(String code) { - super(code); - } - - @ValueRangeProvider(id = "valueRange") - @ProblemFactCollectionProperty - public List getValueList() { - return valueList; - } - - public void setValueList(List valueList) { - this.valueList = valueList; - } - - @PlanningEntityCollectionProperty - public List getEntityList() { - return entityList; - } - - public void setEntityList(List entityList) { - this.entityList = entityList; - } - - @PlanningScore - public SimpleScore getScore() { - return score; - } - - public void setScore(SimpleScore score) { - this.score = score; - } - -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/difficultyweight/TestdataDifficultyWeightValue.java b/core/src/test/java/ai/timefold/solver/core/testdomain/difficultyweight/TestdataDifficultyWeightValue.java deleted file mode 100644 index c1476beca60..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/difficultyweight/TestdataDifficultyWeightValue.java +++ /dev/null @@ -1,11 +0,0 @@ -package ai.timefold.solver.core.testdomain.difficultyweight; - -import ai.timefold.solver.core.testdomain.TestdataObject; - -public class TestdataDifficultyWeightValue extends TestdataObject { - - public TestdataDifficultyWeightValue(String code) { - super(code); - } - -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/equals/TestdataEqualsByCodeObject.java b/core/src/test/java/ai/timefold/solver/core/testdomain/equals/TestdataEqualsByCodeObject.java index c674e87ffbc..43c53af3bad 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/equals/TestdataEqualsByCodeObject.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/equals/TestdataEqualsByCodeObject.java @@ -2,7 +2,7 @@ import java.util.Objects; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.testutil.CodeAssertable; public class TestdataEqualsByCodeObject implements CodeAssertable { diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/equals/list/TestdataEqualsByCodeListObject.java b/core/src/test/java/ai/timefold/solver/core/testdomain/equals/list/TestdataEqualsByCodeListObject.java index 9a0a7facfd0..679c0f1afe7 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/equals/list/TestdataEqualsByCodeListObject.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/equals/list/TestdataEqualsByCodeListObject.java @@ -2,7 +2,7 @@ import java.util.Objects; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.testutil.CodeAssertable; public class TestdataEqualsByCodeListObject implements CodeAssertable { diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/gizmo/GizmoTestdataEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/gizmo/GizmoTestdataEntity.java index f7302f4bbb8..94450decb26 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/gizmo/GizmoTestdataEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/gizmo/GizmoTestdataEntity.java @@ -3,9 +3,9 @@ import java.util.Collection; import java.util.Map; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; import ai.timefold.solver.core.api.domain.entity.PlanningPin; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; import ai.timefold.solver.core.testdomain.TestdataValue; diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/immutable/record/TestdataRecordValue.java b/core/src/test/java/ai/timefold/solver/core/testdomain/immutable/record/TestdataRecordValue.java index 01fbefec3ee..03a6c178049 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/immutable/record/TestdataRecordValue.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/immutable/record/TestdataRecordValue.java @@ -1,6 +1,6 @@ package ai.timefold.solver.core.testdomain.immutable.record; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; public record TestdataRecordValue(@PlanningId String code) { } diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/multiple/baseannotated/classes/childnot/TestdataMultipleChildNotAnnotatedBaseEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/multiple/baseannotated/classes/childnot/TestdataMultipleChildNotAnnotatedBaseEntity.java index 9323355a90e..3a4ee425d74 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/multiple/baseannotated/classes/childnot/TestdataMultipleChildNotAnnotatedBaseEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/multiple/baseannotated/classes/childnot/TestdataMultipleChildNotAnnotatedBaseEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.testdomain.inheritance.entity.multiple.baseannotated.classes.childnot; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/multiple/baseannotated/classes/childtoo/TestdataMultipleBothAnnotatedBaseEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/multiple/baseannotated/classes/childtoo/TestdataMultipleBothAnnotatedBaseEntity.java index 795d4959554..2a70df7f625 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/multiple/baseannotated/classes/childtoo/TestdataMultipleBothAnnotatedBaseEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/multiple/baseannotated/classes/childtoo/TestdataMultipleBothAnnotatedBaseEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.testdomain.inheritance.entity.multiple.baseannotated.classes.childtoo; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/multiple/baseannotated/interfaces/childnot/TestdataMultipleChildNotAnnotatedInterfaceBaseEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/multiple/baseannotated/interfaces/childnot/TestdataMultipleChildNotAnnotatedInterfaceBaseEntity.java index ac60d926593..be022a140d6 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/multiple/baseannotated/interfaces/childnot/TestdataMultipleChildNotAnnotatedInterfaceBaseEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/multiple/baseannotated/interfaces/childnot/TestdataMultipleChildNotAnnotatedInterfaceBaseEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.testdomain.inheritance.entity.multiple.baseannotated.interfaces.childnot; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/multiple/baseannotated/interfaces/childtoo/TestdataMultipleBothAnnotatedInterfaceBaseEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/multiple/baseannotated/interfaces/childtoo/TestdataMultipleBothAnnotatedInterfaceBaseEntity.java index 5c2e9de40a8..fa2af14b589 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/multiple/baseannotated/interfaces/childtoo/TestdataMultipleBothAnnotatedInterfaceBaseEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/multiple/baseannotated/interfaces/childtoo/TestdataMultipleBothAnnotatedInterfaceBaseEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.testdomain.inheritance.entity.multiple.baseannotated.interfaces.childtoo; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/addvar/TestdataAddVarBaseEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/addvar/TestdataAddVarBaseEntity.java index 9f334ea1d0e..7c9e3672ffa 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/addvar/TestdataAddVarBaseEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/addvar/TestdataAddVarBaseEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.testdomain.inheritance.entity.single.baseannotated.classes.addvar; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/childnot/TestdataChildNotAnnotatedBaseEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/childnot/TestdataChildNotAnnotatedBaseEntity.java index 57c8265e20e..c65917d02c0 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/childnot/TestdataChildNotAnnotatedBaseEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/childnot/TestdataChildNotAnnotatedBaseEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.testdomain.inheritance.entity.single.baseannotated.classes.childnot; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/pinned/TestdataExtendedPinnedEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/pinned/TestdataExtendedPinnedEntity.java index 8c936cc38c7..437fdfd70d0 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/pinned/TestdataExtendedPinnedEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/pinned/TestdataExtendedPinnedEntity.java @@ -6,11 +6,10 @@ import ai.timefold.solver.core.testdomain.TestdataValue; import ai.timefold.solver.core.testdomain.pinned.TestdataPinnedEntity; -@PlanningEntity(pinningFilter = TestdataExtendedPinningFilter.class) +@PlanningEntity public class TestdataExtendedPinnedEntity extends TestdataPinnedEntity { private TestdataValue subValue; - private boolean closed; private boolean pinnedByBoss; public TestdataExtendedPinnedEntity() { @@ -25,11 +24,10 @@ public TestdataExtendedPinnedEntity(String code, TestdataValue value, TestdataVa this.subValue = subValue; } - public TestdataExtendedPinnedEntity(String code, TestdataValue value, boolean locked, boolean pinned, - TestdataValue subValue, boolean closed, boolean pinnedByBoss) { - super(code, value, locked, pinned); + public TestdataExtendedPinnedEntity(String code, TestdataValue value, boolean pinned, TestdataValue subValue, + boolean pinnedByBoss) { + super(code, value, pinned); this.subValue = subValue; - this.closed = closed; this.pinnedByBoss = pinnedByBoss; } @@ -42,14 +40,6 @@ public void setSubValue(TestdataValue subValue) { this.subValue = subValue; } - public boolean isClosed() { - return closed; - } - - public void setClosed(boolean closed) { - this.closed = closed; - } - @PlanningPin public boolean isPinnedByBoss() { return pinnedByBoss; diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/pinned/TestdataExtendedPinningFilter.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/pinned/TestdataExtendedPinningFilter.java deleted file mode 100644 index 3936510fcfc..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/pinned/TestdataExtendedPinningFilter.java +++ /dev/null @@ -1,15 +0,0 @@ -package ai.timefold.solver.core.testdomain.inheritance.entity.single.baseannotated.classes.pinned; - -import ai.timefold.solver.core.api.domain.entity.PinningFilter; - -import org.jspecify.annotations.NonNull; - -public class TestdataExtendedPinningFilter - implements PinningFilter { - - @Override - public boolean accept(@NonNull TestdataExtendedPinnedSolution solution, @NonNull TestdataExtendedPinnedEntity entity) { - return entity.isClosed(); - } - -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/replacevar/TestdataReplaceVarBaseEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/replacevar/TestdataReplaceVarBaseEntity.java index 1c57cd5bf01..a0700e9170e 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/replacevar/TestdataReplaceVarBaseEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/classes/replacevar/TestdataReplaceVarBaseEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.testdomain.inheritance.entity.single.baseannotated.classes.replacevar; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/interfaces/addvar/TestdataAddVarInterfaceBaseEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/interfaces/addvar/TestdataAddVarInterfaceBaseEntity.java index 906f4e253fc..32785bd707b 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/interfaces/addvar/TestdataAddVarInterfaceBaseEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/interfaces/addvar/TestdataAddVarInterfaceBaseEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.testdomain.inheritance.entity.single.baseannotated.interfaces.addvar; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/interfaces/childnot/TestdataChildNotAnnotatedInterfaceBaseEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/interfaces/childnot/TestdataChildNotAnnotatedInterfaceBaseEntity.java index 2012822ea21..420d46f754b 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/interfaces/childnot/TestdataChildNotAnnotatedInterfaceBaseEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/interfaces/childnot/TestdataChildNotAnnotatedInterfaceBaseEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.testdomain.inheritance.entity.single.baseannotated.interfaces.childnot; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/interfaces/childtoo/TestdataBaseEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/interfaces/childtoo/TestdataBaseEntity.java index 6bdb226e2dd..d0e028501af 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/interfaces/childtoo/TestdataBaseEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/interfaces/childtoo/TestdataBaseEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.testdomain.inheritance.entity.single.baseannotated.interfaces.childtoo; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/interfaces/replacevar/TestdataReplaceVarInterfaceBaseEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/interfaces/replacevar/TestdataReplaceVarInterfaceBaseEntity.java index aec6b03eaa3..8316b55f903 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/interfaces/replacevar/TestdataReplaceVarInterfaceBaseEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/baseannotated/interfaces/replacevar/TestdataReplaceVarInterfaceBaseEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.testdomain.inheritance.entity.single.baseannotated.interfaces.replacevar; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/basenot/classes/TestdataBaseNotAnnotatedBaseEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/basenot/classes/TestdataBaseNotAnnotatedBaseEntity.java index a4f33849f65..b374d26685a 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/basenot/classes/TestdataBaseNotAnnotatedBaseEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/basenot/classes/TestdataBaseNotAnnotatedBaseEntity.java @@ -1,6 +1,6 @@ package ai.timefold.solver.core.testdomain.inheritance.entity.single.basenot.classes; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; public class TestdataBaseNotAnnotatedBaseEntity { diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/basenot/interfaces/TestdataBaseNotAnnotatedInterfaceBaseEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/basenot/interfaces/TestdataBaseNotAnnotatedInterfaceBaseEntity.java index 06e952f73c2..dd1cd145a6e 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/basenot/interfaces/TestdataBaseNotAnnotatedInterfaceBaseEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/entity/single/basenot/interfaces/TestdataBaseNotAnnotatedInterfaceBaseEntity.java @@ -1,6 +1,6 @@ package ai.timefold.solver.core.testdomain.inheritance.entity.single.basenot.interfaces; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; public interface TestdataBaseNotAnnotatedInterfaceBaseEntity { diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/solution/baseannotated/childtooabstract/TestdataBothAnnotatedAbstractBaseEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/solution/baseannotated/childtooabstract/TestdataBothAnnotatedAbstractBaseEntity.java index fb70f3edc08..63b8a58c3bd 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/solution/baseannotated/childtooabstract/TestdataBothAnnotatedAbstractBaseEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/solution/baseannotated/childtooabstract/TestdataBothAnnotatedAbstractBaseEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.testdomain.inheritance.solution.baseannotated.childtooabstract; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/solution/baseannotated/multiple/TestdataMultipleInheritanceEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/solution/baseannotated/multiple/TestdataMultipleInheritanceEntity.java index 589a9133491..1c751c063a1 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/solution/baseannotated/multiple/TestdataMultipleInheritanceEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/solution/baseannotated/multiple/TestdataMultipleInheritanceEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.testdomain.inheritance.solution.baseannotated.multiple; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/solution/baseannotated/replacemember/TestdataReplaceMemberEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/solution/baseannotated/replacemember/TestdataReplaceMemberEntity.java index 45188f68801..597c302dc13 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/solution/baseannotated/replacemember/TestdataReplaceMemberEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/solution/baseannotated/replacemember/TestdataReplaceMemberEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.testdomain.inheritance.solution.baseannotated.replacemember; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/solution/baseanot/TestdataOnlyAnnotatedBaseEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/solution/baseanot/TestdataOnlyAnnotatedBaseEntity.java index 708ff65e0dc..4a96fb5a9ac 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/solution/baseanot/TestdataOnlyAnnotatedBaseEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/inheritance/solution/baseanot/TestdataOnlyAnnotatedBaseEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.testdomain.inheritance.solution.baseanot; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/interfaces/TestdataInterfaceEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/interfaces/TestdataInterfaceEntity.java index 27c98fea3e9..fdeb9f99d30 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/interfaces/TestdataInterfaceEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/interfaces/TestdataInterfaceEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.testdomain.interfaces; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/list/sort/comparator/TestdataListSortableEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/list/sort/comparator/TestdataListSortableEntity.java index 015ba9ef1c4..258435d6eb0 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/list/sort/comparator/TestdataListSortableEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/list/sort/comparator/TestdataListSortableEntity.java @@ -10,7 +10,7 @@ import ai.timefold.solver.core.testdomain.common.TestSortableObject; import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; -@PlanningEntity(difficultyComparatorClass = TestSortableComparator.class) +@PlanningEntity(comparatorClass = TestSortableComparator.class) public class TestdataListSortableEntity extends TestdataObject implements TestSortableObject { @PlanningListVariable(valueRangeProviderRefs = "valueRange", comparatorClass = TestSortableComparator.class) diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/list/sort/factory/TestdataListFactorySortableEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/list/sort/factory/TestdataListFactorySortableEntity.java index d9b28a0cbc9..1ecfea00c3c 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/list/sort/factory/TestdataListFactorySortableEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/list/sort/factory/TestdataListFactorySortableEntity.java @@ -10,7 +10,7 @@ import ai.timefold.solver.core.testdomain.common.TestSortableObject; import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; -@PlanningEntity(difficultyWeightFactoryClass = TestSortableFactory.class) +@PlanningEntity(comparatorFactoryClass = TestSortableFactory.class) public class TestdataListFactorySortableEntity extends TestdataObject implements TestSortableObject { @PlanningListVariable(valueRangeProviderRefs = "valueRange", comparatorFactoryClass = TestSortableFactory.class) diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/list/valuerange/sort/comparator/TestdataListSortableEntityProvidingEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/list/valuerange/sort/comparator/TestdataListSortableEntityProvidingEntity.java index d31c620292b..95765393bb6 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/list/valuerange/sort/comparator/TestdataListSortableEntityProvidingEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/list/valuerange/sort/comparator/TestdataListSortableEntityProvidingEntity.java @@ -12,7 +12,7 @@ import ai.timefold.solver.core.testdomain.common.TestSortableObject; import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; -@PlanningEntity(difficultyComparatorClass = TestSortableComparator.class) +@PlanningEntity(comparatorClass = TestSortableComparator.class) public class TestdataListSortableEntityProvidingEntity extends TestdataObject implements TestSortableObject { @PlanningListVariable(valueRangeProviderRefs = "valueRange", comparatorClass = TestSortableComparator.class) diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/list/valuerange/sort/factory/TestdataListFactorySortableEntityProvidingEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/list/valuerange/sort/factory/TestdataListFactorySortableEntityProvidingEntity.java index 14e8a45593b..f44f1f7cb3a 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/list/valuerange/sort/factory/TestdataListFactorySortableEntityProvidingEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/list/valuerange/sort/factory/TestdataListFactorySortableEntityProvidingEntity.java @@ -12,7 +12,7 @@ import ai.timefold.solver.core.testdomain.common.TestSortableObject; import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; -@PlanningEntity(difficultyWeightFactoryClass = TestSortableFactory.class) +@PlanningEntity(comparatorFactoryClass = TestSortableFactory.class) public class TestdataListFactorySortableEntityProvidingEntity extends TestdataObject implements TestSortableObject { diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/mixed/multientity/TestdataMixedMultiEntityFirstEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/mixed/multientity/TestdataMixedMultiEntityFirstEntity.java index 77291e68803..385cc9a8b8b 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/mixed/multientity/TestdataMixedMultiEntityFirstEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/mixed/multientity/TestdataMixedMultiEntityFirstEntity.java @@ -7,7 +7,7 @@ import ai.timefold.solver.core.api.domain.variable.PlanningListVariable; import ai.timefold.solver.core.testdomain.TestdataObject; -@PlanningEntity(difficultyComparatorClass = TestdataMixedMultiEntityFirstEntityComparator.class) +@PlanningEntity(comparatorClass = TestdataMixedMultiEntityFirstEntityComparator.class) public class TestdataMixedMultiEntityFirstEntity extends TestdataObject { @PlanningListVariable(valueRangeProviderRefs = "valueRange") diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/mixed/multientity/TestdataMixedMultiEntitySecondEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/mixed/multientity/TestdataMixedMultiEntitySecondEntity.java index 46286546373..cc614e9a12c 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/mixed/multientity/TestdataMixedMultiEntitySecondEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/mixed/multientity/TestdataMixedMultiEntitySecondEntity.java @@ -8,7 +8,7 @@ public class TestdataMixedMultiEntitySecondEntity extends TestdataObject { @PlanningVariable(valueRangeProviderRefs = "otherValueRange", - strengthComparatorClass = TestdataMixedMultiEntitySecondValueComparator.class) + comparatorClass = TestdataMixedMultiEntitySecondValueComparator.class) private TestdataMixedMultiEntitySecondValue basicValue; @PlanningVariable(valueRangeProviderRefs = "otherValueRange") diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/mixed/singleentity/TestdataMixedEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/mixed/singleentity/TestdataMixedEntity.java index cc27bb8ba08..d3e0e7e71ba 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/mixed/singleentity/TestdataMixedEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/mixed/singleentity/TestdataMixedEntity.java @@ -12,11 +12,10 @@ import ai.timefold.solver.core.api.domain.variable.ShadowVariable; import ai.timefold.solver.core.testdomain.TestdataObject; -@PlanningEntity(difficultyComparatorClass = TestdataMixedEntityComparator.class) +@PlanningEntity(comparatorClass = TestdataMixedEntityComparator.class) public class TestdataMixedEntity extends TestdataObject { - @PlanningVariable(valueRangeProviderRefs = "otherValueRange", - strengthComparatorClass = TestdataMixedOtherValueComparator.class) + @PlanningVariable(valueRangeProviderRefs = "otherValueRange", comparatorClass = TestdataMixedOtherValueComparator.class) private TestdataMixedOtherValue basicValue; @PlanningVariable(valueRangeProviderRefs = "otherValueRange") diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/pinned/TestdataPinnedEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/pinned/TestdataPinnedEntity.java index fe94a171ac6..ea1e385d107 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/pinned/TestdataPinnedEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/pinned/TestdataPinnedEntity.java @@ -7,7 +7,7 @@ import ai.timefold.solver.core.testdomain.TestdataObject; import ai.timefold.solver.core.testdomain.TestdataValue; -@PlanningEntity(pinningFilter = TestdataPinningFilter.class) +@PlanningEntity public class TestdataPinnedEntity extends TestdataObject { public static EntityDescriptor buildEntityDescriptor() { @@ -16,7 +16,6 @@ public static EntityDescriptor buildEntityDescriptor() { } private TestdataValue value; - private boolean locked; private boolean pinned; public TestdataPinnedEntity() { @@ -26,20 +25,13 @@ public TestdataPinnedEntity(String code) { super(code); } - public TestdataPinnedEntity(String code, boolean locked, boolean pinned) { - this(code); - this.locked = locked; - this.pinned = pinned; - } - public TestdataPinnedEntity(String code, TestdataValue value) { this(code); this.value = value; } - public TestdataPinnedEntity(String code, TestdataValue value, boolean locked, boolean pinned) { + public TestdataPinnedEntity(String code, TestdataValue value, boolean pinned) { this(code, value); - this.locked = locked; this.pinned = pinned; } @@ -52,14 +44,6 @@ public void setValue(TestdataValue value) { this.value = value; } - public boolean isLocked() { - return locked; - } - - public void setLocked(boolean locked) { - this.locked = locked; - } - @PlanningPin public boolean isPinned() { return pinned; diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/pinned/TestdataPinningFilter.java b/core/src/test/java/ai/timefold/solver/core/testdomain/pinned/TestdataPinningFilter.java deleted file mode 100644 index 137c20458f4..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/pinned/TestdataPinningFilter.java +++ /dev/null @@ -1,14 +0,0 @@ -package ai.timefold.solver.core.testdomain.pinned; - -import ai.timefold.solver.core.api.domain.entity.PinningFilter; - -import org.jspecify.annotations.NonNull; - -public class TestdataPinningFilter implements PinningFilter { - - @Override - public boolean accept(@NonNull TestdataPinnedSolution solution, @NonNull TestdataPinnedEntity entity) { - return entity.isLocked(); - } - -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/pinned/unassignedvar/TestdataAllowsUnassignedPinningFilter.java b/core/src/test/java/ai/timefold/solver/core/testdomain/pinned/unassignedvar/TestdataAllowsUnassignedPinningFilter.java deleted file mode 100644 index 247a00a1f58..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/pinned/unassignedvar/TestdataAllowsUnassignedPinningFilter.java +++ /dev/null @@ -1,16 +0,0 @@ -package ai.timefold.solver.core.testdomain.pinned.unassignedvar; - -import ai.timefold.solver.core.api.domain.entity.PinningFilter; - -import org.jspecify.annotations.NonNull; - -public class TestdataAllowsUnassignedPinningFilter - implements PinningFilter { - - @Override - public boolean accept(@NonNull TestdataPinnedAllowsUnassignedSolution solution, - @NonNull TestdataPinnedAllowsUnassignedEntity entity) { - return entity.isLocked(); - } - -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/pinned/unassignedvar/TestdataPinnedAllowsUnassignedEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/pinned/unassignedvar/TestdataPinnedAllowsUnassignedEntity.java index effd5786685..145c77ac133 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/pinned/unassignedvar/TestdataPinnedAllowsUnassignedEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/pinned/unassignedvar/TestdataPinnedAllowsUnassignedEntity.java @@ -7,7 +7,7 @@ import ai.timefold.solver.core.testdomain.TestdataObject; import ai.timefold.solver.core.testdomain.TestdataValue; -@PlanningEntity(pinningFilter = TestdataAllowsUnassignedPinningFilter.class) +@PlanningEntity public class TestdataPinnedAllowsUnassignedEntity extends TestdataObject { public static EntityDescriptor buildEntityDescriptor() { @@ -16,7 +16,6 @@ public static EntityDescriptor buildEnti } private TestdataValue value; - private boolean locked; private boolean pinned; public TestdataPinnedAllowsUnassignedEntity() { @@ -26,20 +25,13 @@ public TestdataPinnedAllowsUnassignedEntity(String code) { super(code); } - public TestdataPinnedAllowsUnassignedEntity(String code, boolean locked, boolean pinned) { - this(code); - this.locked = locked; - this.pinned = pinned; - } - public TestdataPinnedAllowsUnassignedEntity(String code, TestdataValue value) { this(code); this.value = value; } - public TestdataPinnedAllowsUnassignedEntity(String code, TestdataValue value, boolean locked, boolean pinned) { + public TestdataPinnedAllowsUnassignedEntity(String code, TestdataValue value, boolean pinned) { this(code, value); - this.locked = locked; this.pinned = pinned; } @@ -52,14 +44,6 @@ public void setValue(TestdataValue value) { this.value = value; } - public boolean isLocked() { - return locked; - } - - public void setLocked(boolean locked) { - this.locked = locked; - } - @PlanningPin public boolean isPinned() { return pinned; diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/planningid/TestdataStringPlanningIdEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/planningid/TestdataStringPlanningIdEntity.java index 976e0ddb3ea..9b5723c59ed 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/planningid/TestdataStringPlanningIdEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/planningid/TestdataStringPlanningIdEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.core.testdomain.planningid; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/record/TestdataRecordValue.java b/core/src/test/java/ai/timefold/solver/core/testdomain/record/TestdataRecordValue.java index a5371659a46..16f08afcd09 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/record/TestdataRecordValue.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/record/TestdataRecordValue.java @@ -1,6 +1,6 @@ package ai.timefold.solver.core.testdomain.record; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; public record TestdataRecordValue(@PlanningId String code) { } diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/shadow/concurrent/TestdataConcurrentEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/shadow/concurrent/TestdataConcurrentEntity.java index ef1bee85332..f91a54e819b 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/shadow/concurrent/TestdataConcurrentEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/shadow/concurrent/TestdataConcurrentEntity.java @@ -3,8 +3,8 @@ import java.util.ArrayList; import java.util.List; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningListVariable; @PlanningEntity diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/shadow/concurrent/TestdataConcurrentValue.java b/core/src/test/java/ai/timefold/solver/core/testdomain/shadow/concurrent/TestdataConcurrentValue.java index 81bcd3121a0..36e6edbca91 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/shadow/concurrent/TestdataConcurrentValue.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/shadow/concurrent/TestdataConcurrentValue.java @@ -9,8 +9,8 @@ import java.util.Map; import java.util.Objects; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.CascadingUpdateShadowVariable; import ai.timefold.solver.core.api.domain.variable.IndexShadowVariable; import ai.timefold.solver.core.api.domain.variable.InverseRelationShadowVariable; diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/comparator/TestdataComparatorSortableSolution.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/comparator/TestdataComparatorSortableSolution.java index 60bc41efd98..09671515a94 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/comparator/TestdataComparatorSortableSolution.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/comparator/TestdataComparatorSortableSolution.java @@ -21,8 +21,7 @@ public class TestdataComparatorSortableSolution { public static SolutionDescriptor buildSolutionDescriptor() { return SolutionDescriptor.buildSolutionDescriptor( TestdataComparatorSortableSolution.class, - TestdataComparatorSortableEntity.class, - TestdataSortableValue.class); + TestdataComparatorSortableEntity.class); } public static TestdataComparatorSortableSolution generateSolution(int valueCount, int entityCount, boolean shuffle) { diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/comparatordifficulty/OneValuePerEntityDifficultyEasyScoreCalculator.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/comparatordifficulty/OneValuePerEntityDifficultyEasyScoreCalculator.java deleted file mode 100644 index 1a960d98ec5..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/comparatordifficulty/OneValuePerEntityDifficultyEasyScoreCalculator.java +++ /dev/null @@ -1,27 +0,0 @@ -package ai.timefold.solver.core.testdomain.sort.comparatordifficulty; - -import java.util.Objects; - -import ai.timefold.solver.core.api.score.HardSoftScore; -import ai.timefold.solver.core.api.score.calculator.EasyScoreCalculator; - -import org.jspecify.annotations.NonNull; - -public class OneValuePerEntityDifficultyEasyScoreCalculator - implements EasyScoreCalculator { - - @Override - public @NonNull HardSoftScore calculateScore(@NonNull TestdataDifficultySortableSolution solution) { - var distinct = (int) solution.getEntityList().stream() - .map(TestdataDifficultySortableEntity::getValue) - .filter(Objects::nonNull) - .distinct() - .count(); - var assigned = solution.getEntityList().stream() - .map(TestdataDifficultySortableEntity::getValue) - .filter(Objects::nonNull) - .count(); - var repeated = (int) (assigned - distinct); - return HardSoftScore.of(-repeated, -distinct); - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/comparatordifficulty/TestdataDifficultySortableEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/comparatordifficulty/TestdataDifficultySortableEntity.java deleted file mode 100644 index 3c8ea7ac36c..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/comparatordifficulty/TestdataDifficultySortableEntity.java +++ /dev/null @@ -1,37 +0,0 @@ -package ai.timefold.solver.core.testdomain.sort.comparatordifficulty; - -import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.variable.PlanningVariable; -import ai.timefold.solver.core.testdomain.TestdataObject; -import ai.timefold.solver.core.testdomain.common.TestSortableComparator; -import ai.timefold.solver.core.testdomain.common.TestSortableObject; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningEntity(difficultyComparatorClass = TestSortableComparator.class) -public class TestdataDifficultySortableEntity extends TestdataObject implements TestSortableObject { - - @PlanningVariable(valueRangeProviderRefs = "valueRange", strengthComparatorClass = TestSortableComparator.class) - private TestdataSortableValue value; - private int difficulty; - - public TestdataDifficultySortableEntity() { - } - - public TestdataDifficultySortableEntity(String code, int difficulty) { - super(code); - this.difficulty = difficulty; - } - - public TestdataSortableValue getValue() { - return value; - } - - public void setValue(TestdataSortableValue value) { - this.value = value; - } - - @Override - public int getComparatorValue() { - return difficulty; - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/comparatordifficulty/TestdataDifficultySortableSolution.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/comparatordifficulty/TestdataDifficultySortableSolution.java deleted file mode 100644 index d8a0913da2b..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/comparatordifficulty/TestdataDifficultySortableSolution.java +++ /dev/null @@ -1,83 +0,0 @@ -package ai.timefold.solver.core.testdomain.sort.comparatordifficulty; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; -import java.util.stream.IntStream; - -import ai.timefold.solver.core.api.domain.solution.PlanningEntityCollectionProperty; -import ai.timefold.solver.core.api.domain.solution.PlanningScore; -import ai.timefold.solver.core.api.domain.solution.PlanningSolution; -import ai.timefold.solver.core.api.domain.solution.ProblemFactCollectionProperty; -import ai.timefold.solver.core.api.domain.valuerange.ValueRangeProvider; -import ai.timefold.solver.core.api.score.HardSoftScore; -import ai.timefold.solver.core.impl.domain.solution.descriptor.SolutionDescriptor; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningSolution -public class TestdataDifficultySortableSolution { - - public static SolutionDescriptor buildSolutionDescriptor() { - return SolutionDescriptor.buildSolutionDescriptor( - TestdataDifficultySortableSolution.class, - TestdataDifficultySortableEntity.class, - TestdataSortableValue.class); - } - - public static TestdataDifficultySortableSolution generateSolution(int valueCount, int entityCount, boolean shuffle) { - var entityList = new ArrayList<>(IntStream.range(0, entityCount) - .mapToObj(i -> new TestdataDifficultySortableEntity("Generated Entity " + i, i)) - .toList()); - var valueList = new ArrayList<>(IntStream.range(0, valueCount) - .mapToObj(i -> new TestdataSortableValue("Generated Value " + i, i)) - .toList()); - if (shuffle) { - var random = new Random(0); - Collections.shuffle(entityList, random); - Collections.shuffle(valueList, random); - } - TestdataDifficultySortableSolution solution = new TestdataDifficultySortableSolution(); - solution.setValueList(valueList); - solution.setEntityList(entityList); - return solution; - } - - private List valueList; - private List entityList; - private HardSoftScore score; - - @ValueRangeProvider(id = "valueRange") - @ProblemFactCollectionProperty - public List getValueList() { - return valueList; - } - - public void setValueList(List valueList) { - this.valueList = valueList; - } - - @PlanningEntityCollectionProperty - public List getEntityList() { - return entityList; - } - - public void setEntityList(List entityList) { - this.entityList = entityList; - } - - @PlanningScore - public HardSoftScore getScore() { - return score; - } - - public void setScore(HardSoftScore score) { - this.score = score; - } - - public void removeEntity(TestdataDifficultySortableEntity entity) { - this.entityList = entityList.stream() - .filter(e -> e != entity) - .toList(); - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/factorydifficulty/OneValuePerEntityDifficultyFactoryEasyScoreCalculator.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/factorydifficulty/OneValuePerEntityDifficultyFactoryEasyScoreCalculator.java deleted file mode 100644 index 07bf11e764d..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/factorydifficulty/OneValuePerEntityDifficultyFactoryEasyScoreCalculator.java +++ /dev/null @@ -1,28 +0,0 @@ -package ai.timefold.solver.core.testdomain.sort.factorydifficulty; - -import java.util.Objects; - -import ai.timefold.solver.core.api.score.HardSoftScore; -import ai.timefold.solver.core.api.score.calculator.EasyScoreCalculator; - -import org.jspecify.annotations.NonNull; - -public class OneValuePerEntityDifficultyFactoryEasyScoreCalculator - implements EasyScoreCalculator { - - @Override - public @NonNull HardSoftScore - calculateScore(@NonNull TestdataDifficultyFactorySortableSolution solution) { - var distinct = (int) solution.getEntityList().stream() - .map(TestdataDifficultyFactorySortableEntity::getValue) - .filter(Objects::nonNull) - .distinct() - .count(); - var assigned = solution.getEntityList().stream() - .map(TestdataDifficultyFactorySortableEntity::getValue) - .filter(Objects::nonNull) - .count(); - var repeated = (int) (assigned - distinct); - return HardSoftScore.of(-repeated, -distinct); - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/factorydifficulty/TestdataDifficultyFactorySortableEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/factorydifficulty/TestdataDifficultyFactorySortableEntity.java deleted file mode 100644 index c45b154a898..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/factorydifficulty/TestdataDifficultyFactorySortableEntity.java +++ /dev/null @@ -1,37 +0,0 @@ -package ai.timefold.solver.core.testdomain.sort.factorydifficulty; - -import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.variable.PlanningVariable; -import ai.timefold.solver.core.testdomain.TestdataObject; -import ai.timefold.solver.core.testdomain.common.TestSortableFactory; -import ai.timefold.solver.core.testdomain.common.TestSortableObject; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningEntity(difficultyWeightFactoryClass = TestSortableFactory.class) -public class TestdataDifficultyFactorySortableEntity extends TestdataObject implements TestSortableObject { - - @PlanningVariable(valueRangeProviderRefs = "valueRange", strengthWeightFactoryClass = TestSortableFactory.class) - private TestdataSortableValue value; - private int difficulty; - - public TestdataDifficultyFactorySortableEntity() { - } - - public TestdataDifficultyFactorySortableEntity(String code, int difficulty) { - super(code); - this.difficulty = difficulty; - } - - public TestdataSortableValue getValue() { - return value; - } - - public void setValue(TestdataSortableValue value) { - this.value = value; - } - - @Override - public int getComparatorValue() { - return difficulty; - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/factorydifficulty/TestdataDifficultyFactorySortableSolution.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/factorydifficulty/TestdataDifficultyFactorySortableSolution.java deleted file mode 100644 index eb87d7ced59..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/factorydifficulty/TestdataDifficultyFactorySortableSolution.java +++ /dev/null @@ -1,83 +0,0 @@ -package ai.timefold.solver.core.testdomain.sort.factorydifficulty; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; -import java.util.stream.IntStream; - -import ai.timefold.solver.core.api.domain.solution.PlanningEntityCollectionProperty; -import ai.timefold.solver.core.api.domain.solution.PlanningScore; -import ai.timefold.solver.core.api.domain.solution.PlanningSolution; -import ai.timefold.solver.core.api.domain.solution.ProblemFactCollectionProperty; -import ai.timefold.solver.core.api.domain.valuerange.ValueRangeProvider; -import ai.timefold.solver.core.api.score.HardSoftScore; -import ai.timefold.solver.core.impl.domain.solution.descriptor.SolutionDescriptor; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningSolution -public class TestdataDifficultyFactorySortableSolution { - - public static SolutionDescriptor buildSolutionDescriptor() { - return SolutionDescriptor.buildSolutionDescriptor( - TestdataDifficultyFactorySortableSolution.class, - TestdataDifficultyFactorySortableEntity.class, - TestdataSortableValue.class); - } - - public static TestdataDifficultyFactorySortableSolution generateSolution(int valueCount, int entityCount, boolean shuffle) { - var entityList = new ArrayList<>(IntStream.range(0, entityCount) - .mapToObj(i -> new TestdataDifficultyFactorySortableEntity("Generated Entity " + i, i)) - .toList()); - var valueList = new ArrayList<>(IntStream.range(0, valueCount) - .mapToObj(i -> new TestdataSortableValue("Generated Value " + i, i)) - .toList()); - if (shuffle) { - var random = new Random(0); - Collections.shuffle(entityList, random); - Collections.shuffle(valueList, random); - } - TestdataDifficultyFactorySortableSolution solution = new TestdataDifficultyFactorySortableSolution(); - solution.setValueList(valueList); - solution.setEntityList(entityList); - return solution; - } - - private List valueList; - private List entityList; - private HardSoftScore score; - - @ValueRangeProvider(id = "valueRange") - @ProblemFactCollectionProperty - public List getValueList() { - return valueList; - } - - public void setValueList(List valueList) { - this.valueList = valueList; - } - - @PlanningEntityCollectionProperty - public List getEntityList() { - return entityList; - } - - public void setEntityList(List entityList) { - this.entityList = entityList; - } - - @PlanningScore - public HardSoftScore getScore() { - return score; - } - - public void setScore(HardSoftScore score) { - this.score = score; - } - - public void removeEntity(TestdataDifficultyFactorySortableEntity entity) { - this.entityList = entityList.stream() - .filter(e -> e != entity) - .toList(); - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/mixed/comparator/TestdataInvalidMixedComparatorSortableEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/TestdataInvalidMixedComparatorSortableEntity.java similarity index 94% rename from core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/mixed/comparator/TestdataInvalidMixedComparatorSortableEntity.java rename to core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/TestdataInvalidMixedComparatorSortableEntity.java index b664a20a7dd..dcd18fd5f77 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/mixed/comparator/TestdataInvalidMixedComparatorSortableEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/TestdataInvalidMixedComparatorSortableEntity.java @@ -1,4 +1,4 @@ -package ai.timefold.solver.core.testdomain.sort.invalid.mixed.comparator; +package ai.timefold.solver.core.testdomain.sort.invalid; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/mixed/comparator/TestdataInvalidMixedComparatorSortableSolution.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/TestdataInvalidMixedComparatorSortableSolution.java similarity index 95% rename from core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/mixed/comparator/TestdataInvalidMixedComparatorSortableSolution.java rename to core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/TestdataInvalidMixedComparatorSortableSolution.java index 0b8d29613a8..bc7e3045606 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/mixed/comparator/TestdataInvalidMixedComparatorSortableSolution.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/TestdataInvalidMixedComparatorSortableSolution.java @@ -1,4 +1,4 @@ -package ai.timefold.solver.core.testdomain.sort.invalid.mixed.comparator; +package ai.timefold.solver.core.testdomain.sort.invalid; import java.util.List; diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/mixed/strength/TestdataInvalidMixedStrengthSortableEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/mixed/strength/TestdataInvalidMixedStrengthSortableEntity.java deleted file mode 100644 index 1e9a8605202..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/mixed/strength/TestdataInvalidMixedStrengthSortableEntity.java +++ /dev/null @@ -1,41 +0,0 @@ -package ai.timefold.solver.core.testdomain.sort.invalid.mixed.strength; - -import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.variable.PlanningVariable; -import ai.timefold.solver.core.testdomain.TestdataObject; -import ai.timefold.solver.core.testdomain.common.DummyValueComparator; -import ai.timefold.solver.core.testdomain.common.DummyWeightValueFactory; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningEntity -public class TestdataInvalidMixedStrengthSortableEntity extends TestdataObject { - - @PlanningVariable(valueRangeProviderRefs = "valueRange", strengthComparatorClass = DummyValueComparator.class, - strengthWeightFactoryClass = DummyWeightValueFactory.class) - private TestdataSortableValue value; - private int difficulty; - - public TestdataInvalidMixedStrengthSortableEntity() { - } - - public TestdataInvalidMixedStrengthSortableEntity(String code, int difficulty) { - super(code); - this.difficulty = difficulty; - } - - public TestdataSortableValue getValue() { - return value; - } - - public void setValue(TestdataSortableValue value) { - this.value = value; - } - - public int getDifficulty() { - return difficulty; - } - - public void setDifficulty(int difficulty) { - this.difficulty = difficulty; - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/mixed/strength/TestdataInvalidMixedStrengthSortableSolution.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/mixed/strength/TestdataInvalidMixedStrengthSortableSolution.java deleted file mode 100644 index e6dfca0cd7f..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/mixed/strength/TestdataInvalidMixedStrengthSortableSolution.java +++ /dev/null @@ -1,52 +0,0 @@ -package ai.timefold.solver.core.testdomain.sort.invalid.mixed.strength; - -import java.util.List; - -import ai.timefold.solver.core.api.domain.solution.PlanningEntityCollectionProperty; -import ai.timefold.solver.core.api.domain.solution.PlanningScore; -import ai.timefold.solver.core.api.domain.solution.PlanningSolution; -import ai.timefold.solver.core.api.domain.valuerange.ValueRangeProvider; -import ai.timefold.solver.core.api.score.HardSoftScore; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningSolution -public class TestdataInvalidMixedStrengthSortableSolution { - - private List valueList; - private List entityList; - private HardSoftScore score; - - @ValueRangeProvider(id = "valueRange") - @PlanningEntityCollectionProperty - public List getValueList() { - return valueList; - } - - public void setValueList(List valueList) { - this.valueList = valueList; - } - - @PlanningEntityCollectionProperty - public List getEntityList() { - return entityList; - } - - public void setEntityList(List entityList) { - this.entityList = entityList; - } - - @PlanningScore - public HardSoftScore getScore() { - return score; - } - - public void setScore(HardSoftScore score) { - this.score = score; - } - - public void removeEntity(TestdataInvalidMixedStrengthSortableEntity entity) { - this.entityList = entityList.stream() - .filter(e -> e != entity) - .toList(); - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twocomparator/entity/TestdataInvalidTwoEntityComparatorSortableEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twocomparator/entity/TestdataInvalidTwoEntityComparatorSortableEntity.java deleted file mode 100644 index 0258960aceb..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twocomparator/entity/TestdataInvalidTwoEntityComparatorSortableEntity.java +++ /dev/null @@ -1,39 +0,0 @@ -package ai.timefold.solver.core.testdomain.sort.invalid.twocomparator.entity; - -import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.variable.PlanningVariable; -import ai.timefold.solver.core.testdomain.TestdataObject; -import ai.timefold.solver.core.testdomain.common.DummyValueComparator; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningEntity(comparatorClass = DummyValueComparator.class, difficultyComparatorClass = DummyValueComparator.class) -public class TestdataInvalidTwoEntityComparatorSortableEntity extends TestdataObject { - - @PlanningVariable(valueRangeProviderRefs = "valueRange", comparatorClass = DummyValueComparator.class) - private TestdataSortableValue value; - private int difficulty; - - public TestdataInvalidTwoEntityComparatorSortableEntity() { - } - - public TestdataInvalidTwoEntityComparatorSortableEntity(String code, int difficulty) { - super(code); - this.difficulty = difficulty; - } - - public TestdataSortableValue getValue() { - return value; - } - - public void setValue(TestdataSortableValue value) { - this.value = value; - } - - public int getDifficulty() { - return difficulty; - } - - public void setDifficulty(int difficulty) { - this.difficulty = difficulty; - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twocomparator/entity/TestdataInvalidTwoEntityComparatorSortableSolution.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twocomparator/entity/TestdataInvalidTwoEntityComparatorSortableSolution.java deleted file mode 100644 index 4c1dc03698e..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twocomparator/entity/TestdataInvalidTwoEntityComparatorSortableSolution.java +++ /dev/null @@ -1,52 +0,0 @@ -package ai.timefold.solver.core.testdomain.sort.invalid.twocomparator.entity; - -import java.util.List; - -import ai.timefold.solver.core.api.domain.solution.PlanningEntityCollectionProperty; -import ai.timefold.solver.core.api.domain.solution.PlanningScore; -import ai.timefold.solver.core.api.domain.solution.PlanningSolution; -import ai.timefold.solver.core.api.domain.valuerange.ValueRangeProvider; -import ai.timefold.solver.core.api.score.HardSoftScore; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningSolution -public class TestdataInvalidTwoEntityComparatorSortableSolution { - - private List valueList; - private List entityList; - private HardSoftScore score; - - @ValueRangeProvider(id = "valueRange") - @PlanningEntityCollectionProperty - public List getValueList() { - return valueList; - } - - public void setValueList(List valueList) { - this.valueList = valueList; - } - - @PlanningEntityCollectionProperty - public List getEntityList() { - return entityList; - } - - public void setEntityList(List entityList) { - this.entityList = entityList; - } - - @PlanningScore - public HardSoftScore getScore() { - return score; - } - - public void setScore(HardSoftScore score) { - this.score = score; - } - - public void removeEntity(TestdataInvalidTwoEntityComparatorSortableEntity entity) { - this.entityList = entityList.stream() - .filter(e -> e != entity) - .toList(); - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twocomparator/value/TestdataInvalidTwoValueComparatorSortableEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twocomparator/value/TestdataInvalidTwoValueComparatorSortableEntity.java deleted file mode 100644 index bdbbaa19bd4..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twocomparator/value/TestdataInvalidTwoValueComparatorSortableEntity.java +++ /dev/null @@ -1,40 +0,0 @@ -package ai.timefold.solver.core.testdomain.sort.invalid.twocomparator.value; - -import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.variable.PlanningVariable; -import ai.timefold.solver.core.testdomain.TestdataObject; -import ai.timefold.solver.core.testdomain.common.DummyValueComparator; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningEntity -public class TestdataInvalidTwoValueComparatorSortableEntity extends TestdataObject { - - @PlanningVariable(valueRangeProviderRefs = "valueRange", comparatorClass = DummyValueComparator.class, - strengthComparatorClass = DummyValueComparator.class) - private TestdataSortableValue value; - private int difficulty; - - public TestdataInvalidTwoValueComparatorSortableEntity() { - } - - public TestdataInvalidTwoValueComparatorSortableEntity(String code, int difficulty) { - super(code); - this.difficulty = difficulty; - } - - public TestdataSortableValue getValue() { - return value; - } - - public void setValue(TestdataSortableValue value) { - this.value = value; - } - - public int getDifficulty() { - return difficulty; - } - - public void setDifficulty(int difficulty) { - this.difficulty = difficulty; - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twocomparator/value/TestdataInvalidTwoValueComparatorSortableSolution.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twocomparator/value/TestdataInvalidTwoValueComparatorSortableSolution.java deleted file mode 100644 index cbb52907449..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twocomparator/value/TestdataInvalidTwoValueComparatorSortableSolution.java +++ /dev/null @@ -1,52 +0,0 @@ -package ai.timefold.solver.core.testdomain.sort.invalid.twocomparator.value; - -import java.util.List; - -import ai.timefold.solver.core.api.domain.solution.PlanningEntityCollectionProperty; -import ai.timefold.solver.core.api.domain.solution.PlanningScore; -import ai.timefold.solver.core.api.domain.solution.PlanningSolution; -import ai.timefold.solver.core.api.domain.valuerange.ValueRangeProvider; -import ai.timefold.solver.core.api.score.HardSoftScore; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningSolution -public class TestdataInvalidTwoValueComparatorSortableSolution { - - private List valueList; - private List entityList; - private HardSoftScore score; - - @ValueRangeProvider(id = "valueRange") - @PlanningEntityCollectionProperty - public List getValueList() { - return valueList; - } - - public void setValueList(List valueList) { - this.valueList = valueList; - } - - @PlanningEntityCollectionProperty - public List getEntityList() { - return entityList; - } - - public void setEntityList(List entityList) { - this.entityList = entityList; - } - - @PlanningScore - public HardSoftScore getScore() { - return score; - } - - public void setScore(HardSoftScore score) { - this.score = score; - } - - public void removeEntity(TestdataInvalidTwoValueComparatorSortableEntity entity) { - this.entityList = entityList.stream() - .filter(e -> e != entity) - .toList(); - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twofactory/entity/TestdataInvalidTwoEntityFactorySortableEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twofactory/entity/TestdataInvalidTwoEntityFactorySortableEntity.java deleted file mode 100644 index 5c37dff2c79..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twofactory/entity/TestdataInvalidTwoEntityFactorySortableEntity.java +++ /dev/null @@ -1,39 +0,0 @@ -package ai.timefold.solver.core.testdomain.sort.invalid.twofactory.entity; - -import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.variable.PlanningVariable; -import ai.timefold.solver.core.testdomain.TestdataObject; -import ai.timefold.solver.core.testdomain.common.DummyValueFactory; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningEntity(comparatorFactoryClass = DummyValueFactory.class, difficultyWeightFactoryClass = DummyValueFactory.class) -public class TestdataInvalidTwoEntityFactorySortableEntity extends TestdataObject { - - @PlanningVariable(valueRangeProviderRefs = "valueRange", comparatorFactoryClass = DummyValueFactory.class) - private TestdataSortableValue value; - private int difficulty; - - public TestdataInvalidTwoEntityFactorySortableEntity() { - } - - public TestdataInvalidTwoEntityFactorySortableEntity(String code, int difficulty) { - super(code); - this.difficulty = difficulty; - } - - public TestdataSortableValue getValue() { - return value; - } - - public void setValue(TestdataSortableValue value) { - this.value = value; - } - - public int getDifficulty() { - return difficulty; - } - - public void setDifficulty(int difficulty) { - this.difficulty = difficulty; - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twofactory/entity/TestdataInvalidTwoEntityFactorySortableSolution.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twofactory/entity/TestdataInvalidTwoEntityFactorySortableSolution.java deleted file mode 100644 index 23e8d98916b..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twofactory/entity/TestdataInvalidTwoEntityFactorySortableSolution.java +++ /dev/null @@ -1,52 +0,0 @@ -package ai.timefold.solver.core.testdomain.sort.invalid.twofactory.entity; - -import java.util.List; - -import ai.timefold.solver.core.api.domain.solution.PlanningEntityCollectionProperty; -import ai.timefold.solver.core.api.domain.solution.PlanningScore; -import ai.timefold.solver.core.api.domain.solution.PlanningSolution; -import ai.timefold.solver.core.api.domain.valuerange.ValueRangeProvider; -import ai.timefold.solver.core.api.score.HardSoftScore; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningSolution -public class TestdataInvalidTwoEntityFactorySortableSolution { - - private List valueList; - private List entityList; - private HardSoftScore score; - - @ValueRangeProvider(id = "valueRange") - @PlanningEntityCollectionProperty - public List getValueList() { - return valueList; - } - - public void setValueList(List valueList) { - this.valueList = valueList; - } - - @PlanningEntityCollectionProperty - public List getEntityList() { - return entityList; - } - - public void setEntityList(List entityList) { - this.entityList = entityList; - } - - @PlanningScore - public HardSoftScore getScore() { - return score; - } - - public void setScore(HardSoftScore score) { - this.score = score; - } - - public void removeEntity(TestdataInvalidTwoEntityFactorySortableEntity entity) { - this.entityList = entityList.stream() - .filter(e -> e != entity) - .toList(); - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twofactory/value/TestdataInvalidTwoValueFactorySortableEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twofactory/value/TestdataInvalidTwoValueFactorySortableEntity.java deleted file mode 100644 index d7592e526c3..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twofactory/value/TestdataInvalidTwoValueFactorySortableEntity.java +++ /dev/null @@ -1,41 +0,0 @@ -package ai.timefold.solver.core.testdomain.sort.invalid.twofactory.value; - -import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.variable.PlanningVariable; -import ai.timefold.solver.core.testdomain.TestdataObject; -import ai.timefold.solver.core.testdomain.common.DummyValueFactory; -import ai.timefold.solver.core.testdomain.common.DummyWeightValueFactory; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningEntity -public class TestdataInvalidTwoValueFactorySortableEntity extends TestdataObject { - - @PlanningVariable(valueRangeProviderRefs = "valueRange", comparatorFactoryClass = DummyValueFactory.class, - strengthWeightFactoryClass = DummyWeightValueFactory.class) - private TestdataSortableValue value; - private int difficulty; - - public TestdataInvalidTwoValueFactorySortableEntity() { - } - - public TestdataInvalidTwoValueFactorySortableEntity(String code, int difficulty) { - super(code); - this.difficulty = difficulty; - } - - public TestdataSortableValue getValue() { - return value; - } - - public void setValue(TestdataSortableValue value) { - this.value = value; - } - - public int getDifficulty() { - return difficulty; - } - - public void setDifficulty(int difficulty) { - this.difficulty = difficulty; - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twofactory/value/TestdataInvalidTwoValueFactorySortableSolution.java b/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twofactory/value/TestdataInvalidTwoValueFactorySortableSolution.java deleted file mode 100644 index c40f210e8b8..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/sort/invalid/twofactory/value/TestdataInvalidTwoValueFactorySortableSolution.java +++ /dev/null @@ -1,52 +0,0 @@ -package ai.timefold.solver.core.testdomain.sort.invalid.twofactory.value; - -import java.util.List; - -import ai.timefold.solver.core.api.domain.solution.PlanningEntityCollectionProperty; -import ai.timefold.solver.core.api.domain.solution.PlanningScore; -import ai.timefold.solver.core.api.domain.solution.PlanningSolution; -import ai.timefold.solver.core.api.domain.valuerange.ValueRangeProvider; -import ai.timefold.solver.core.api.score.HardSoftScore; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningSolution -public class TestdataInvalidTwoValueFactorySortableSolution { - - private List valueList; - private List entityList; - private HardSoftScore score; - - @ValueRangeProvider(id = "valueRange") - @PlanningEntityCollectionProperty - public List getValueList() { - return valueList; - } - - public void setValueList(List valueList) { - this.valueList = valueList; - } - - @PlanningEntityCollectionProperty - public List getEntityList() { - return entityList; - } - - public void setEntityList(List entityList) { - this.entityList = entityList; - } - - @PlanningScore - public HardSoftScore getScore() { - return score; - } - - public void setScore(HardSoftScore score) { - this.score = score; - } - - public void removeEntity(TestdataInvalidTwoValueFactorySortableEntity entity) { - this.entityList = entityList.stream() - .filter(e -> e != entity) - .toList(); - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/comparator/TestdataComparatorSortableEntityProvidingEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/comparator/TestdataComparatorSortableEntityProvidingEntity.java index 8fc6b593bd8..857d0171558 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/comparator/TestdataComparatorSortableEntityProvidingEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/comparator/TestdataComparatorSortableEntityProvidingEntity.java @@ -11,10 +11,10 @@ import ai.timefold.solver.core.testdomain.common.TestSortableObject; import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; -@PlanningEntity(difficultyComparatorClass = TestSortableComparator.class) +@PlanningEntity(comparatorClass = TestSortableComparator.class) public class TestdataComparatorSortableEntityProvidingEntity extends TestdataObject implements TestSortableObject { - @PlanningVariable(valueRangeProviderRefs = "valueRange", strengthComparatorClass = TestSortableComparator.class) + @PlanningVariable(valueRangeProviderRefs = "valueRange", comparatorClass = TestSortableComparator.class) private TestdataSortableValue value; @ValueRangeProvider(id = "valueRange") @PlanningEntityCollectionProperty diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/comparatorstrength/OneValuePerEntityStrengthRangeEasyScoreCalculator.java b/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/comparatorstrength/OneValuePerEntityStrengthRangeEasyScoreCalculator.java deleted file mode 100644 index 90962e78a8d..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/comparatorstrength/OneValuePerEntityStrengthRangeEasyScoreCalculator.java +++ /dev/null @@ -1,28 +0,0 @@ -package ai.timefold.solver.core.testdomain.valuerange.sort.comparatorstrength; - -import java.util.Objects; - -import ai.timefold.solver.core.api.score.HardSoftScore; -import ai.timefold.solver.core.api.score.calculator.EasyScoreCalculator; - -import org.jspecify.annotations.NonNull; - -public class OneValuePerEntityStrengthRangeEasyScoreCalculator - implements EasyScoreCalculator { - - @Override - public @NonNull HardSoftScore - calculateScore(@NonNull TestdataStrengthSortableEntityProvidingSolution solution) { - var distinct = (int) solution.getEntityList().stream() - .map(TestdataStrengthSortableEntityProvidingEntity::getValue) - .filter(Objects::nonNull) - .distinct() - .count(); - var assigned = solution.getEntityList().stream() - .map(TestdataStrengthSortableEntityProvidingEntity::getValue) - .filter(Objects::nonNull) - .count(); - var repeated = (int) (assigned - distinct); - return HardSoftScore.of(-repeated, -distinct); - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/comparatorstrength/TestdataStrengthSortableEntityProvidingEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/comparatorstrength/TestdataStrengthSortableEntityProvidingEntity.java deleted file mode 100644 index d9a8a4b30ac..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/comparatorstrength/TestdataStrengthSortableEntityProvidingEntity.java +++ /dev/null @@ -1,53 +0,0 @@ -package ai.timefold.solver.core.testdomain.valuerange.sort.comparatorstrength; - -import java.util.List; - -import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.solution.PlanningEntityCollectionProperty; -import ai.timefold.solver.core.api.domain.valuerange.ValueRangeProvider; -import ai.timefold.solver.core.api.domain.variable.PlanningVariable; -import ai.timefold.solver.core.testdomain.TestdataObject; -import ai.timefold.solver.core.testdomain.common.TestSortableComparator; -import ai.timefold.solver.core.testdomain.common.TestSortableObject; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningEntity(difficultyComparatorClass = TestSortableComparator.class) -public class TestdataStrengthSortableEntityProvidingEntity extends TestdataObject implements TestSortableObject { - - @PlanningVariable(valueRangeProviderRefs = "valueRange", strengthComparatorClass = TestSortableComparator.class) - private TestdataSortableValue value; - @ValueRangeProvider(id = "valueRange") - @PlanningEntityCollectionProperty - private List valueRange; - - private int difficulty; - - public TestdataStrengthSortableEntityProvidingEntity() { - } - - public TestdataStrengthSortableEntityProvidingEntity(String code, int difficulty) { - super(code); - this.difficulty = difficulty; - } - - public TestdataSortableValue getValue() { - return value; - } - - public void setValue(TestdataSortableValue value) { - this.value = value; - } - - public List getValueRange() { - return valueRange; - } - - public void setValueRange(List valueRange) { - this.valueRange = valueRange; - } - - @Override - public int getComparatorValue() { - return difficulty; - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/comparatorstrength/TestdataStrengthSortableEntityProvidingSolution.java b/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/comparatorstrength/TestdataStrengthSortableEntityProvidingSolution.java deleted file mode 100644 index 877949ee3f2..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/comparatorstrength/TestdataStrengthSortableEntityProvidingSolution.java +++ /dev/null @@ -1,75 +0,0 @@ -package ai.timefold.solver.core.testdomain.valuerange.sort.comparatorstrength; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; -import java.util.stream.IntStream; - -import ai.timefold.solver.core.api.domain.solution.PlanningEntityCollectionProperty; -import ai.timefold.solver.core.api.domain.solution.PlanningScore; -import ai.timefold.solver.core.api.domain.solution.PlanningSolution; -import ai.timefold.solver.core.api.score.HardSoftScore; -import ai.timefold.solver.core.impl.domain.solution.descriptor.SolutionDescriptor; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningSolution -public class TestdataStrengthSortableEntityProvidingSolution { - - public static SolutionDescriptor buildSolutionDescriptor() { - return SolutionDescriptor.buildSolutionDescriptor( - TestdataStrengthSortableEntityProvidingSolution.class, - TestdataStrengthSortableEntityProvidingEntity.class); - } - - public static TestdataStrengthSortableEntityProvidingSolution generateSolution(int valueCount, int entityCount, - boolean shuffle) { - var entityList = new ArrayList<>(IntStream.range(0, entityCount) - .mapToObj(i -> new TestdataStrengthSortableEntityProvidingEntity("Generated Entity " + i, i)) - .toList()); - var valueList = IntStream.range(0, valueCount) - .mapToObj(i -> new TestdataSortableValue("Generated Value " + i, i)) - .toList(); - var random = new Random(0); - var solution = new TestdataStrengthSortableEntityProvidingSolution(); - for (var entity : entityList) { - var valueRange = new ArrayList<>(valueList); - if (shuffle) { - Collections.shuffle(valueRange, random); - } - entity.setValueRange(valueRange); - } - if (shuffle) { - Collections.shuffle(entityList, random); - } - solution.setEntityList(entityList); - return solution; - } - - private List entityList; - private HardSoftScore score; - - @PlanningEntityCollectionProperty - public List getEntityList() { - return entityList; - } - - public void setEntityList(List entityList) { - this.entityList = entityList; - } - - @PlanningScore - public HardSoftScore getScore() { - return score; - } - - public void setScore(HardSoftScore score) { - this.score = score; - } - - public void removeEntity(TestdataStrengthSortableEntityProvidingEntity entity) { - this.entityList = entityList.stream() - .filter(e -> e != entity) - .toList(); - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/factory/TestdataFactorySortableEntityProvidingEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/factory/TestdataFactorySortableEntityProvidingEntity.java index 9e59a830d9c..dbc1c917452 100644 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/factory/TestdataFactorySortableEntityProvidingEntity.java +++ b/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/factory/TestdataFactorySortableEntityProvidingEntity.java @@ -11,7 +11,7 @@ import ai.timefold.solver.core.testdomain.common.TestSortableObject; import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; -@PlanningEntity(difficultyWeightFactoryClass = TestSortableFactory.class) +@PlanningEntity(comparatorFactoryClass = TestSortableFactory.class) public class TestdataFactorySortableEntityProvidingEntity extends TestdataObject implements TestSortableObject { diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/factorystrength/OneValuePerEntityStrengthFactoryRangeEasyScoreCalculator.java b/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/factorystrength/OneValuePerEntityStrengthFactoryRangeEasyScoreCalculator.java deleted file mode 100644 index ea6c0c8b16b..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/factorystrength/OneValuePerEntityStrengthFactoryRangeEasyScoreCalculator.java +++ /dev/null @@ -1,29 +0,0 @@ -package ai.timefold.solver.core.testdomain.valuerange.sort.factorystrength; - -import java.util.Objects; - -import ai.timefold.solver.core.api.score.HardSoftScore; -import ai.timefold.solver.core.api.score.calculator.EasyScoreCalculator; - -import org.jspecify.annotations.NonNull; - -public class OneValuePerEntityStrengthFactoryRangeEasyScoreCalculator - implements EasyScoreCalculator { - - @Override - public @NonNull HardSoftScore - calculateScore( - @NonNull TestdataStrengthFactorySortableEntityProvidingSolution solution) { - var distinct = (int) solution.getEntityList().stream() - .map(TestdataStrengthFactorySortableEntityProvidingEntity::getValue) - .filter(Objects::nonNull) - .distinct() - .count(); - var assigned = solution.getEntityList().stream() - .map(TestdataStrengthFactorySortableEntityProvidingEntity::getValue) - .filter(Objects::nonNull) - .count(); - var repeated = (int) (assigned - distinct); - return HardSoftScore.of(-repeated, -distinct); - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/factorystrength/TestdataStrengthFactorySortableEntityProvidingEntity.java b/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/factorystrength/TestdataStrengthFactorySortableEntityProvidingEntity.java deleted file mode 100644 index 2c342cae16e..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/factorystrength/TestdataStrengthFactorySortableEntityProvidingEntity.java +++ /dev/null @@ -1,54 +0,0 @@ -package ai.timefold.solver.core.testdomain.valuerange.sort.factorystrength; - -import java.util.List; - -import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.solution.PlanningEntityCollectionProperty; -import ai.timefold.solver.core.api.domain.valuerange.ValueRangeProvider; -import ai.timefold.solver.core.api.domain.variable.PlanningVariable; -import ai.timefold.solver.core.testdomain.TestdataObject; -import ai.timefold.solver.core.testdomain.common.TestSortableFactory; -import ai.timefold.solver.core.testdomain.common.TestSortableObject; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningEntity(difficultyWeightFactoryClass = TestSortableFactory.class) -public class TestdataStrengthFactorySortableEntityProvidingEntity extends TestdataObject - implements TestSortableObject { - - @PlanningVariable(valueRangeProviderRefs = "valueRange", strengthWeightFactoryClass = TestSortableFactory.class) - private TestdataSortableValue value; - @ValueRangeProvider(id = "valueRange") - @PlanningEntityCollectionProperty - private List valueRange; - - private int difficulty; - - public TestdataStrengthFactorySortableEntityProvidingEntity() { - } - - public TestdataStrengthFactorySortableEntityProvidingEntity(String code, int difficulty) { - super(code); - this.difficulty = difficulty; - } - - public TestdataSortableValue getValue() { - return value; - } - - public void setValue(TestdataSortableValue value) { - this.value = value; - } - - public List getValueRange() { - return valueRange; - } - - public void setValueRange(List valueRange) { - this.valueRange = valueRange; - } - - @Override - public int getComparatorValue() { - return difficulty; - } -} diff --git a/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/factorystrength/TestdataStrengthFactorySortableEntityProvidingSolution.java b/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/factorystrength/TestdataStrengthFactorySortableEntityProvidingSolution.java deleted file mode 100644 index 5ef6904ab00..00000000000 --- a/core/src/test/java/ai/timefold/solver/core/testdomain/valuerange/sort/factorystrength/TestdataStrengthFactorySortableEntityProvidingSolution.java +++ /dev/null @@ -1,75 +0,0 @@ -package ai.timefold.solver.core.testdomain.valuerange.sort.factorystrength; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Random; -import java.util.stream.IntStream; - -import ai.timefold.solver.core.api.domain.solution.PlanningEntityCollectionProperty; -import ai.timefold.solver.core.api.domain.solution.PlanningScore; -import ai.timefold.solver.core.api.domain.solution.PlanningSolution; -import ai.timefold.solver.core.api.score.HardSoftScore; -import ai.timefold.solver.core.impl.domain.solution.descriptor.SolutionDescriptor; -import ai.timefold.solver.core.testdomain.common.TestdataSortableValue; - -@PlanningSolution -public class TestdataStrengthFactorySortableEntityProvidingSolution { - - public static SolutionDescriptor buildSolutionDescriptor() { - return SolutionDescriptor.buildSolutionDescriptor( - TestdataStrengthFactorySortableEntityProvidingSolution.class, - TestdataStrengthFactorySortableEntityProvidingEntity.class); - } - - public static TestdataStrengthFactorySortableEntityProvidingSolution generateSolution(int valueCount, int entityCount, - boolean shuffle) { - var entityList = new ArrayList<>(IntStream.range(0, entityCount) - .mapToObj(i -> new TestdataStrengthFactorySortableEntityProvidingEntity("Generated Entity " + i, i)) - .toList()); - var valueList = IntStream.range(0, valueCount) - .mapToObj(i -> new TestdataSortableValue("Generated Value " + i, i)) - .toList(); - var solution = new TestdataStrengthFactorySortableEntityProvidingSolution(); - var random = new Random(0); - for (var entity : entityList) { - var valueRange = new ArrayList<>(valueList); - if (shuffle) { - Collections.shuffle(valueRange, random); - } - entity.setValueRange(valueRange); - } - if (shuffle) { - Collections.shuffle(entityList, random); - } - solution.setEntityList(entityList); - return solution; - } - - private List entityList; - private HardSoftScore score; - - @PlanningEntityCollectionProperty - public List getEntityList() { - return entityList; - } - - public void setEntityList(List entityList) { - this.entityList = entityList; - } - - @PlanningScore - public HardSoftScore getScore() { - return score; - } - - public void setScore(HardSoftScore score) { - this.score = score; - } - - public void removeEntity(TestdataStrengthFactorySortableEntityProvidingEntity entity) { - this.entityList = entityList.stream() - .filter(e -> e != entity) - .toList(); - } -} diff --git a/docs/TODO.md b/docs/TODO.md index f3370ba42fa..a463be529a7 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -26,5 +26,9 @@ - [ ] The solver now implicitly trusts equals() on objects, such as entities and values. - [ ] BestSolutionChangedEvent now an interface. (All constructors were deprecated anyway.) - [ ] ProblemFactChange -> ProblemChange, migration script? +- [ ] PinningFilter is gone, so is strengths and difficulties, and nullable. +- [ ] PlanningId moves from domain.lookup to domain.entity. +- [ ] domain.lookup package is gone, so is lookup from PlanningSolution. +- [ ] lookups no longer accept null values. Remove this file when done. \ No newline at end of file diff --git a/docs/src/modules/ROOT/pages/quickstart/quarkus-vehicle-routing/vehicle-routing-model.adoc b/docs/src/modules/ROOT/pages/quickstart/quarkus-vehicle-routing/vehicle-routing-model.adoc index b82e01dba8e..38f11d5dd31 100644 --- a/docs/src/modules/ROOT/pages/quickstart/quarkus-vehicle-routing/vehicle-routing-model.adoc +++ b/docs/src/modules/ROOT/pages/quickstart/quarkus-vehicle-routing/vehicle-routing-model.adoc @@ -121,7 +121,7 @@ import java.util.ArrayList; import java.util.List; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.entity.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningListVariable; @PlanningEntity @@ -196,7 +196,7 @@ import java.time.LocalDateTime import java.util.ArrayList import ai.timefold.solver.core.api.domain.entity.PlanningEntity -import ai.timefold.solver.core.api.domain.lookup.PlanningId +import ai.timefold.solver.core.api.domain.entity.PlanningId import ai.timefold.solver.core.api.domain.variable.PlanningListVariable @PlanningEntity @@ -292,7 +292,7 @@ import java.time.Duration; import java.time.LocalDateTime; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.entity.PlanningId; import ai.timefold.solver.core.api.domain.variable.InverseRelationShadowVariable; import ai.timefold.solver.core.api.domain.variable.NextElementShadowVariable; import ai.timefold.solver.core.api.domain.variable.PreviousElementShadowVariable; @@ -404,7 +404,7 @@ import java.time.Duration import java.time.LocalDateTime import ai.timefold.solver.core.api.domain.entity.PlanningEntity -import ai.timefold.solver.core.api.domain.lookup.PlanningId +import ai.timefold.solver.core.api.domain.entity.PlanningId import ai.timefold.solver.core.api.domain.variable.InverseRelationShadowVariable import ai.timefold.solver.core.api.domain.variable.NextElementShadowVariable import ai.timefold.solver.core.api.domain.variable.PreviousElementShadowVariable diff --git a/docs/src/modules/ROOT/pages/quickstart/shared/school-timetabling/school-timetabling-model.adoc b/docs/src/modules/ROOT/pages/quickstart/shared/school-timetabling/school-timetabling-model.adoc index fb27dc75c7e..ce3beb65366 100644 --- a/docs/src/modules/ROOT/pages/quickstart/shared/school-timetabling/school-timetabling-model.adoc +++ b/docs/src/modules/ROOT/pages/quickstart/shared/school-timetabling/school-timetabling-model.adoc @@ -197,7 +197,7 @@ Create the `src/main/java/org/acme/schooltimetabling/domain/Lesson.java` class: package org.acme.schooltimetabling.domain; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.entity.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity @@ -283,7 +283,7 @@ Create the `src/main/kotlin/org/acme/schooltimetabling/domain/Lesson.kt` class: package org.acme.schooltimetabling.domain import ai.timefold.solver.core.api.domain.entity.PlanningEntity -import ai.timefold.solver.core.api.domain.lookup.PlanningId +import ai.timefold.solver.core.api.domain.entity.PlanningId import ai.timefold.solver.core.api.domain.variable.PlanningVariable @PlanningEntity diff --git a/quarkus-integration/quarkus-benchmark/integration-test/src/main/java/ai/timefold/solver/quarkus/benchmark/it/domain/TestdataStringLengthShadowEntity.java b/quarkus-integration/quarkus-benchmark/integration-test/src/main/java/ai/timefold/solver/quarkus/benchmark/it/domain/TestdataStringLengthShadowEntity.java index 01a9fb4f9c9..7aec71ede08 100644 --- a/quarkus-integration/quarkus-benchmark/integration-test/src/main/java/ai/timefold/solver/quarkus/benchmark/it/domain/TestdataStringLengthShadowEntity.java +++ b/quarkus-integration/quarkus-benchmark/integration-test/src/main/java/ai/timefold/solver/quarkus/benchmark/it/domain/TestdataStringLengthShadowEntity.java @@ -3,8 +3,8 @@ import java.util.ArrayList; import java.util.List; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningListVariable; @PlanningEntity diff --git a/quarkus-integration/quarkus/deployment/src/main/java/ai/timefold/solver/quarkus/deployment/DotNames.java b/quarkus-integration/quarkus/deployment/src/main/java/ai/timefold/solver/quarkus/deployment/DotNames.java index 3a1add344c9..1b4b29b35e7 100644 --- a/quarkus-integration/quarkus/deployment/src/main/java/ai/timefold/solver/quarkus/deployment/DotNames.java +++ b/quarkus-integration/quarkus/deployment/src/main/java/ai/timefold/solver/quarkus/deployment/DotNames.java @@ -7,10 +7,10 @@ import jakarta.inject.Named; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; import ai.timefold.solver.core.api.domain.entity.PlanningPin; import ai.timefold.solver.core.api.domain.entity.PlanningPinToIndex; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.solution.ConstraintWeightOverrides; import ai.timefold.solver.core.api.domain.solution.PlanningEntityCollectionProperty; import ai.timefold.solver.core.api.domain.solution.PlanningEntityProperty; diff --git a/quarkus-integration/quarkus/deployment/src/test/java/ai/timefold/solver/quarkus/testdomain/gizmo/PrivateNoArgsConstructorEntity.java b/quarkus-integration/quarkus/deployment/src/test/java/ai/timefold/solver/quarkus/testdomain/gizmo/PrivateNoArgsConstructorEntity.java index 210a3e5b9dd..77c06a2a0df 100644 --- a/quarkus-integration/quarkus/deployment/src/test/java/ai/timefold/solver/quarkus/testdomain/gizmo/PrivateNoArgsConstructorEntity.java +++ b/quarkus-integration/quarkus/deployment/src/test/java/ai/timefold/solver/quarkus/testdomain/gizmo/PrivateNoArgsConstructorEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.quarkus.testdomain.gizmo; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity diff --git a/quarkus-integration/quarkus/deployment/src/test/java/ai/timefold/solver/quarkus/testdomain/superclass/TestdataAbstractIdentifiable.java b/quarkus-integration/quarkus/deployment/src/test/java/ai/timefold/solver/quarkus/testdomain/superclass/TestdataAbstractIdentifiable.java index f8bd265dc6f..750d2053b5c 100644 --- a/quarkus-integration/quarkus/deployment/src/test/java/ai/timefold/solver/quarkus/testdomain/superclass/TestdataAbstractIdentifiable.java +++ b/quarkus-integration/quarkus/deployment/src/test/java/ai/timefold/solver/quarkus/testdomain/superclass/TestdataAbstractIdentifiable.java @@ -1,6 +1,6 @@ package ai.timefold.solver.quarkus.testdomain.superclass; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; +import ai.timefold.solver.core.api.domain.common.PlanningId; abstract class TestdataAbstractIdentifiable { diff --git a/spring-integration/spring-boot-integration-test/src/main/java/ai/timefold/solver/spring/boot/it/domain/IntegrationTestEntity.java b/spring-integration/spring-boot-integration-test/src/main/java/ai/timefold/solver/spring/boot/it/domain/IntegrationTestEntity.java index 6ea913ce9cf..f04d792c2aa 100644 --- a/spring-integration/spring-boot-integration-test/src/main/java/ai/timefold/solver/spring/boot/it/domain/IntegrationTestEntity.java +++ b/spring-integration/spring-boot-integration-test/src/main/java/ai/timefold/solver/spring/boot/it/domain/IntegrationTestEntity.java @@ -2,8 +2,8 @@ import java.util.List; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.valuerange.ValueRangeProvider; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; import ai.timefold.solver.core.api.domain.variable.ShadowSources; diff --git a/tools/test/src/test/java/ai/timefold/solver/test/api/testdomain/TestdataConstraintVerifierSecondEntity.java b/tools/test/src/test/java/ai/timefold/solver/test/api/testdomain/TestdataConstraintVerifierSecondEntity.java index f55e4f69883..68d63058904 100644 --- a/tools/test/src/test/java/ai/timefold/solver/test/api/testdomain/TestdataConstraintVerifierSecondEntity.java +++ b/tools/test/src/test/java/ai/timefold/solver/test/api/testdomain/TestdataConstraintVerifierSecondEntity.java @@ -1,7 +1,7 @@ package ai.timefold.solver.test.api.testdomain; +import ai.timefold.solver.core.api.domain.common.PlanningId; import ai.timefold.solver.core.api.domain.entity.PlanningEntity; -import ai.timefold.solver.core.api.domain.lookup.PlanningId; import ai.timefold.solver.core.api.domain.variable.PlanningVariable; @PlanningEntity