or(@NonNull TriPredicate super A, ? super B, ? super C> other) {
Objects.requireNonNull(other);
return (A a, B b, C c) -> test(a, b, c) || other.test(a, b, c);
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/Score.java b/core/src/main/java/ai/timefold/solver/core/api/score/Score.java
index 2b54827925..10c62c8cbf 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/Score.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/Score.java
@@ -8,6 +8,8 @@
import ai.timefold.solver.core.api.score.buildin.simplebigdecimal.SimpleBigDecimalScore;
import ai.timefold.solver.core.api.score.buildin.simplelong.SimpleLongScore;
+import org.jspecify.annotations.NonNull;
+
/**
* A Score is result of the score function (AKA fitness function) on a single possible solution.
*
@@ -59,6 +61,7 @@ default int getInitScore() {
* @param newInitScore always negative (except in statistical calculations), 0 if all planning variables are initialized
* @return equals score except that {@link #initScore()} is set to {@code newInitScore}
*/
+ @NonNull
Score_ withInitScore(int newInitScore);
/**
@@ -67,7 +70,8 @@ default int getInitScore() {
* @param addend value to be added to this Score
* @return this + addend
*/
- Score_ add(Score_ addend);
+ @NonNull
+ Score_ add(@NonNull Score_ addend);
/**
* Returns a Score whose value is (this - subtrahend).
@@ -75,7 +79,8 @@ default int getInitScore() {
* @param subtrahend value to be subtracted from this Score
* @return this - subtrahend, rounded as necessary
*/
- Score_ subtract(Score_ subtrahend);
+ @NonNull
+ Score_ subtract(@NonNull Score_ subtrahend);
/**
* Returns a Score whose value is (this * multiplicand).
@@ -87,6 +92,7 @@ default int getInitScore() {
* @param multiplicand value to be multiplied by this Score.
* @return this * multiplicand
*/
+ @NonNull
Score_ multiply(double multiplicand);
/**
@@ -99,6 +105,7 @@ default int getInitScore() {
* @param divisor value by which this Score is to be divided
* @return this / divisor
*/
+ @NonNull
Score_ divide(double divisor);
/**
@@ -111,6 +118,7 @@ default int getInitScore() {
* @param exponent value by which this Score is to be powered
* @return this ^ exponent
*/
+ @NonNull
Score_ power(double exponent);
/**
@@ -118,7 +126,7 @@ default int getInitScore() {
*
* @return - this
*/
- default Score_ negate() {
+ default @NonNull Score_ negate() {
Score_ zero = zero();
Score_ current = (Score_) this;
if (zero.equals(current)) {
@@ -129,16 +137,14 @@ default Score_ negate() {
/**
* Returns a Score whose value is the absolute value of the score, i.e. |this|.
- *
- * @return never null
*/
+ @NonNull
Score_ abs();
/**
* Returns a Score, all levels of which are zero.
- *
- * @return never null
*/
+ @NonNull
Score_ zero();
/**
@@ -161,16 +167,14 @@ default boolean isZero() {
* The level numbers do not contain the {@link #initScore()}.
* For example: {@code -3init/-0hard/-7soft} also returns {@code new int{-0, -7}}
*
- * @return never null
*/
- Number[] toLevelNumbers();
+ @NonNull
+ Number @NonNull [] toLevelNumbers();
/**
* As defined by {@link #toLevelNumbers()}, only returns double[] instead of Number[].
- *
- * @return never null
*/
- default double[] toLevelDoubles() {
+ default double @NonNull [] toLevelDoubles() {
Number[] levelNumbers = toLevelNumbers();
double[] levelDoubles = new double[levelNumbers.length];
for (int i = 0; i < levelNumbers.length; i++) {
@@ -205,9 +209,8 @@ default boolean isSolutionInitialized() {
*
* Do not use this format to persist information as text, use {@link Object#toString()} instead,
* so it can be parsed reliably.
- *
- * @return never null
*/
+ @NonNull
String toShortString();
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/ScoreExplanation.java b/core/src/main/java/ai/timefold/solver/core/api/score/ScoreExplanation.java
index 79ace01a7a..28091328e6 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/ScoreExplanation.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/ScoreExplanation.java
@@ -18,6 +18,8 @@
import ai.timefold.solver.core.api.score.stream.DefaultConstraintJustification;
import ai.timefold.solver.core.api.solver.SolutionManager;
+import org.jspecify.annotations.NonNull;
+
/**
* Build by {@link SolutionManager#explain(Object)} to hold {@link ConstraintMatchTotal}s and {@link Indictment}s
* necessary to explain the quality of a particular {@link Score}.
@@ -31,18 +33,16 @@ public interface ScoreExplanation> {
/**
* Retrieve the {@link PlanningSolution} that the score being explained comes from.
- *
- * @return never null
*/
+ @NonNull
Solution_ getSolution();
/**
* Return the {@link Score} being explained.
* If the specific {@link Score} type used by the {@link PlanningSolution} is required,
* call {@link #getSolution()} and retrieve it from there.
- *
- * @return never null
*/
+ @NonNull
Score_ getScore();
/**
@@ -56,9 +56,8 @@ public interface ScoreExplanation> {
* Instead, to provide this information in a UI or a service,
* use {@link ScoreExplanation#getConstraintMatchTotalMap()} and {@link ScoreExplanation#getIndictmentMap()}
* and convert those into a domain-specific API.
- *
- * @return never null
*/
+ @NonNull
String getSummary();
/**
@@ -66,10 +65,11 @@ public interface ScoreExplanation> {
*
* The sum of {@link ConstraintMatchTotal#getScore()} equals {@link #getScore()}.
*
- * @return never null, the key is the constraintId
+ * @return the key is the constraintId
* (to create one, use {@link ConstraintRef#composeConstraintId(String, String)}).
* @see #getIndictmentMap()
*/
+ @NonNull
Map> getConstraintMatchTotalMap();
/**
@@ -90,9 +90,10 @@ public interface ScoreExplanation> {
*
*
*
- * @return never null, all constraint matches
+ * @return all constraint matches
* @see #getIndictmentMap()
*/
+ @NonNull
List getJustificationList();
/**
@@ -100,12 +101,11 @@ public interface ScoreExplanation> {
* justified with a given {@link ConstraintJustification} type.
* Otherwise, as defined by {@link #getJustificationList()}.
*
- * @param constraintJustificationClass never null
- * @return never null, all constraint matches associated with the given justification class
+ * @return all constraint matches associated with the given justification class
* @see #getIndictmentMap()
*/
- default List
- getJustificationList(Class extends ConstraintJustification_> constraintJustificationClass) {
+ default @NonNull List
+ getJustificationList(@NonNull Class extends ConstraintJustification_> constraintJustificationClass) {
return getJustificationList()
.stream()
.filter(constraintJustification -> constraintJustificationClass
@@ -123,10 +123,11 @@ public interface ScoreExplanation> {
* because each {@link ConstraintMatch#getScore()} is counted
* for each of the {@link ConstraintMatch#getIndictedObjectList() indicted objects}.
*
- * @return never null, the key is a {@link ProblemFactCollectionProperty problem fact} or a
+ * @return the key is a {@link ProblemFactCollectionProperty problem fact} or a
* {@link PlanningEntity planning entity}
* @see #getConstraintMatchTotalMap()
*/
+ @NonNull
Map> getIndictmentMap();
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/analysis/ConstraintAnalysis.java b/core/src/main/java/ai/timefold/solver/core/api/score/analysis/ConstraintAnalysis.java
index 05621ae14c..93710351a2 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/analysis/ConstraintAnalysis.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/analysis/ConstraintAnalysis.java
@@ -18,31 +18,33 @@
import ai.timefold.solver.core.impl.score.constraint.DefaultConstraintMatchTotal;
import ai.timefold.solver.core.impl.util.CollectionUtils;
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
/**
* Note: Users should never create instances of this type directly.
* It is available transitively via {@link SolutionManager#analyze(Object)}.
*
* @param
- * @param constraintRef never null
- * @param weight never null
- * @param score never null
* @param matches null if analysis not available;
* empty if constraint has no matches, but still non-zero constraint weight;
* non-empty if constraint has matches.
* This is a {@link List} to simplify access to individual elements,
* but it contains no duplicates just like {@link HashSet} wouldn't.
*/
-public record ConstraintAnalysis>(ConstraintRef constraintRef, Score_ weight,
- Score_ score, List> matches) {
+public record ConstraintAnalysis>(@NonNull ConstraintRef constraintRef, @NonNull Score_ weight,
+ @NonNull Score_ score, @Nullable List> matches) {
- static > ConstraintAnalysis of(ConstraintRef constraintRef, Score_ constraintWeight,
- Score_ score) {
+ static > @NonNull ConstraintAnalysis of(
+ @NonNull ConstraintRef constraintRef,
+ @NonNull Score_ constraintWeight,
+ @NonNull Score_ score) {
return new ConstraintAnalysis<>(constraintRef, constraintWeight, score, null);
}
public ConstraintAnalysis {
Objects.requireNonNull(constraintRef);
- if (weight == null) {
+ if (weight == null) { // TODO: clarify - why illegal arg exception vs NPE from requireNonNull?
/*
* Only possible in ConstraintMatchAwareIncrementalScoreCalculator and/or tests.
* Easy doesn't support constraint analysis at all.
@@ -172,18 +174,16 @@ public String constraintPackage() {
*
* @return equal to {@code constraintRef.constraintName()}
*/
- public String constraintName() {
+ public @NonNull String constraintName() {
return constraintRef.constraintName();
}
/**
* Returns a diagnostic text that explains part of the score quality through the {@link ConstraintAnalysis} API.
* The string is built fresh every time the method is called.
- *
- * @return never null
*/
@SuppressWarnings("java:S3457")
- public String summarize() {
+ public @NonNull String summarize() {
var summary = new StringBuilder();
summary.append("""
Explanation of score (%s):
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/analysis/MatchAnalysis.java b/core/src/main/java/ai/timefold/solver/core/api/score/analysis/MatchAnalysis.java
index 1729bf04b2..7f9acdfe4f 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/analysis/MatchAnalysis.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/analysis/MatchAnalysis.java
@@ -8,17 +8,16 @@
import ai.timefold.solver.core.api.score.stream.ConstraintProvider;
import ai.timefold.solver.core.api.solver.SolutionManager;
+import org.jspecify.annotations.NonNull;
+
/**
* Note: Users should never create instances of this type directly.
* It is available transitively via {@link SolutionManager#analyze(Object)}.
*
* @param
- * @param constraintRef never null
- * @param score never null
- * @param justification never null
*/
-public record MatchAnalysis>(ConstraintRef constraintRef, Score_ score,
- ConstraintJustification justification) implements Comparable> {
+public record MatchAnalysis>(@NonNull ConstraintRef constraintRef, @NonNull Score_ score,
+ @NonNull ConstraintJustification justification) implements Comparable> {
public MatchAnalysis {
Objects.requireNonNull(constraintRef);
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/analysis/ScoreAnalysis.java b/core/src/main/java/ai/timefold/solver/core/api/score/analysis/ScoreAnalysis.java
index 0454a36adc..413d0acbec 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/analysis/ScoreAnalysis.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/analysis/ScoreAnalysis.java
@@ -20,6 +20,9 @@
import ai.timefold.solver.core.api.score.stream.ConstraintJustification;
import ai.timefold.solver.core.api.solver.SolutionManager;
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
/**
* Represents the breakdown of a {@link Score} into individual {@link ConstraintAnalysis} instances,
* one for each constraint.
@@ -41,9 +44,7 @@
* Note: the constructors of this record are off-limits.
* We ask users to use exclusively {@link SolutionManager#analyze(Object)} to obtain instances of this record.
*
- * @param score never null
- * @param constraintMap never null;
- * for each constraint identified by its {@link Constraint#getConstraintRef()},
+ * @param constraintMap for each constraint identified by its {@link Constraint#getConstraintRef()},
* the {@link ConstraintAnalysis} that describes the impact of that constraint on the overall score.
* Constraints are present even if they have no matches, unless their weight is zero;
* zero-weight constraints are not present.
@@ -52,8 +53,8 @@
*
* @param
*/
-public record ScoreAnalysis>(Score_ score,
- Map> constraintMap) {
+public record ScoreAnalysis>(@NonNull Score_ score,
+ @NonNull Map> constraintMap) {
static final int DEFAULT_SUMMARY_CONSTRAINT_MATCH_LIMIT = 3;
@@ -78,10 +79,9 @@ public record ScoreAnalysis>(Score_ score,
* Performs a lookup on {@link #constraintMap()}.
* Equivalent to {@code constraintMap().get(constraintRef)}.
*
- * @param constraintRef never null
* @return null if no constraint matches of such constraint are present
*/
- public ConstraintAnalysis getConstraintAnalysis(ConstraintRef constraintRef) {
+ public @Nullable ConstraintAnalysis getConstraintAnalysis(@NonNull ConstraintRef constraintRef) {
return constraintMap.get(constraintRef);
}
@@ -89,20 +89,18 @@ public ConstraintAnalysis getConstraintAnalysis(ConstraintRef constraint
* As defined by {@link #getConstraintAnalysis(ConstraintRef)}
* where the arguments are first composed into a singular constraint ID.
*
- * @param constraintPackage never null
- * @param constraintName never null
* @return null if no constraint matches of such constraint are present
* @deprecated Use {@link #getConstraintAnalysis(String)} instead.
*/
@Deprecated(forRemoval = true, since = "1.13.0")
- public ConstraintAnalysis getConstraintAnalysis(String constraintPackage, String constraintName) {
+ public @Nullable ConstraintAnalysis getConstraintAnalysis(@NonNull String constraintPackage,
+ @NonNull String constraintName) {
return getConstraintAnalysis(ConstraintRef.of(constraintPackage, constraintName));
}
/**
* As defined by {@link #getConstraintAnalysis(ConstraintRef)}.
*
- * @param constraintName never null
* @return null if no constraint matches of such constraint are present
* @throws IllegalStateException if multiple constraints with the same name are present,
* which is possible if they are in different constraint packages.
@@ -110,7 +108,7 @@ public ConstraintAnalysis getConstraintAnalysis(String constraintPackage
* If you must use constraint packages, see {@link #getConstraintAnalysis(String, String)}
* (also deprecated) and reach out to us to discuss your use case.
*/
- public ConstraintAnalysis getConstraintAnalysis(String constraintName) {
+ public @Nullable ConstraintAnalysis getConstraintAnalysis(@NonNull String constraintName) {
var constraintAnalysisList = constraintMap.entrySet()
.stream()
.filter(entry -> entry.getKey().constraintName().equals(constraintName))
@@ -146,11 +144,8 @@ Multiple constraints with the same name (%s) are present in the score analysis.
*
* If one {@link ScoreAnalysis} provides {@link MatchAnalysis} and the other doesn't, exception is thrown.
* Such {@link ScoreAnalysis} instances are mutually incompatible.
- *
- * @param other never null
- * @return never null
*/
- public ScoreAnalysis diff(ScoreAnalysis other) {
+ public @NonNull ScoreAnalysis diff(@NonNull ScoreAnalysis other) {
var result = Stream.concat(constraintMap.keySet().stream(),
other.constraintMap.keySet().stream())
.distinct()
@@ -187,11 +182,9 @@ public Collection> constraintAnalyses() {
* Instead, provide this information in a UI or a service,
* use {@link ScoreAnalysis#constraintAnalyses()}
* and convert those into a domain-specific API.
- *
- * @return never null
*/
@SuppressWarnings("java:S3457")
- public String summarize() {
+ public @NonNull String summarize() {
StringBuilder summary = new StringBuilder();
summary.append("""
Explanation of score (%s):
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/bendable/BendableScore.java b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/bendable/BendableScore.java
index 0d6d74051f..4ae5b3f53b 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/bendable/BendableScore.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/bendable/BendableScore.java
@@ -8,6 +8,8 @@
import ai.timefold.solver.core.impl.score.ScoreUtil;
import ai.timefold.solver.core.impl.score.buildin.BendableScoreDefinition;
+import org.jspecify.annotations.NonNull;
+
/**
* This {@link Score} is based on n levels of int constraints.
* The number of levels is bendable at configuration time.
@@ -21,11 +23,7 @@
*/
public final class BendableScore implements IBendableScore {
- /**
- * @param scoreString never null
- * @return never null
- */
- public static BendableScore parseScore(String scoreString) {
+ public static @NonNull BendableScore parseScore(@NonNull String scoreString) {
String[][] scoreTokens = ScoreUtil.parseBendableScoreTokens(BendableScore.class, scoreString);
int initScore = ScoreUtil.parseInitScore(BendableScore.class, scoreString, scoreTokens[0][0]);
int[] hardScores = new int[scoreTokens[1].length];
@@ -43,22 +41,21 @@ public static BendableScore parseScore(String scoreString) {
* Creates a new {@link BendableScore}.
*
* @param initScore see {@link Score#initScore()}
- * @param hardScores never null, never change that array afterwards: it must be immutable
- * @param softScores never null, never change that array afterwards: it must be immutable
- * @return never null
+ * @param hardScores never change that array afterwards: it must be immutable
+ * @param softScores never change that array afterwards: it must be immutable
*/
- public static BendableScore ofUninitialized(int initScore, int[] hardScores, int[] softScores) {
+ public static @NonNull BendableScore ofUninitialized(int initScore, int @NonNull [] hardScores,
+ int @NonNull [] softScores) {
return new BendableScore(initScore, hardScores, softScores);
}
/**
* Creates a new {@link BendableScore}.
*
- * @param hardScores never null, never change that array afterwards: it must be immutable
- * @param softScores never null, never change that array afterwards: it must be immutable
- * @return never null
+ * @param hardScores never change that array afterwards: it must be immutable
+ * @param softScores never change that array afterwards: it must be immutable
*/
- public static BendableScore of(int[] hardScores, int[] softScores) {
+ public static @NonNull BendableScore of(int @NonNull [] hardScores, int @NonNull [] softScores) {
return new BendableScore(0, hardScores, softScores);
}
@@ -67,9 +64,8 @@ public static BendableScore of(int[] hardScores, int[] softScores) {
*
* @param hardLevelsSize at least 0
* @param softLevelsSize at least 0
- * @return never null
*/
- public static BendableScore zero(int hardLevelsSize, int softLevelsSize) {
+ public static @NonNull BendableScore zero(int hardLevelsSize, int softLevelsSize) {
return new BendableScore(0, new int[hardLevelsSize], new int[softLevelsSize]);
}
@@ -80,9 +76,8 @@ public static BendableScore zero(int hardLevelsSize, int softLevelsSize) {
* @param softLevelsSize at least 0
* @param hardLevel at least 0, less than hardLevelsSize
* @param hardScore any
- * @return never null
*/
- public static BendableScore ofHard(int hardLevelsSize, int softLevelsSize, int hardLevel, int hardScore) {
+ public static @NonNull BendableScore ofHard(int hardLevelsSize, int softLevelsSize, int hardLevel, int hardScore) {
int[] hardScores = new int[hardLevelsSize];
hardScores[hardLevel] = hardScore;
return new BendableScore(0, hardScores, new int[softLevelsSize]);
@@ -95,9 +90,8 @@ public static BendableScore ofHard(int hardLevelsSize, int softLevelsSize, int h
* @param softLevelsSize at least 0
* @param softLevel at least 0, less than softLevelsSize
* @param softScore any
- * @return never null
*/
- public static BendableScore ofSoft(int hardLevelsSize, int softLevelsSize, int softLevel, int softScore) {
+ public static @NonNull BendableScore ofSoft(int hardLevelsSize, int softLevelsSize, int softLevel, int softScore) {
int[] softScores = new int[softLevelsSize];
softScores[softLevel] = softScore;
return new BendableScore(0, new int[hardLevelsSize], softScores);
@@ -118,15 +112,13 @@ public static BendableScore ofSoft(int hardLevelsSize, int softLevelsSize, int s
*/
@SuppressWarnings("unused")
private BendableScore() {
- this(Integer.MIN_VALUE, null, null);
+ this(Integer.MIN_VALUE, new int[] {}, new int[] {});
}
/**
* @param initScore see {@link Score#initScore()}
- * @param hardScores never null
- * @param softScores never null
*/
- private BendableScore(int initScore, int[] hardScores, int[] softScores) {
+ private BendableScore(int initScore, int @NonNull [] hardScores, int @NonNull [] softScores) {
this.initScore = initScore;
this.hardScores = hardScores;
this.softScores = softScores;
@@ -138,9 +130,9 @@ public int initScore() {
}
/**
- * @return not null, array copy because this class is immutable
+ * @return array copy because this class is immutable
*/
- public int[] hardScores() {
+ public int @NonNull [] hardScores() {
return Arrays.copyOf(hardScores, hardScores.length);
}
@@ -150,14 +142,14 @@ public int[] hardScores() {
* @deprecated Use {@link #hardScores()} instead.
*/
@Deprecated(forRemoval = true)
- public int[] getHardScores() {
+ public int @NonNull [] getHardScores() {
return hardScores();
}
/**
- * @return not null, array copy because this class is immutable
+ * @return array copy because this class is immutable
*/
- public int[] softScores() {
+ public int @NonNull [] softScores() {
return Arrays.copyOf(softScores, softScores.length);
}
@@ -167,7 +159,7 @@ public int[] softScores() {
* @deprecated Use {@link #softScores()} instead.
*/
@Deprecated(forRemoval = true)
- public int[] getSoftScores() {
+ public int @NonNull [] getSoftScores() {
return softScores();
}
@@ -224,7 +216,7 @@ public int getSoftScore(int hardLevel) {
// ************************************************************************
@Override
- public BendableScore withInitScore(int newInitScore) {
+ public @NonNull BendableScore withInitScore(int newInitScore) {
return new BendableScore(newInitScore, hardScores, softScores);
}
@@ -264,7 +256,7 @@ public boolean isFeasible() {
}
@Override
- public BendableScore add(BendableScore addend) {
+ public @NonNull BendableScore add(@NonNull BendableScore addend) {
validateCompatible(addend);
int[] newHardScores = new int[hardScores.length];
int[] newSoftScores = new int[softScores.length];
@@ -280,7 +272,7 @@ public BendableScore add(BendableScore addend) {
}
@Override
- public BendableScore subtract(BendableScore subtrahend) {
+ public @NonNull BendableScore subtract(@NonNull BendableScore subtrahend) {
validateCompatible(subtrahend);
int[] newHardScores = new int[hardScores.length];
int[] newSoftScores = new int[softScores.length];
@@ -296,7 +288,7 @@ public BendableScore subtract(BendableScore subtrahend) {
}
@Override
- public BendableScore multiply(double multiplicand) {
+ public @NonNull BendableScore multiply(double multiplicand) {
int[] newHardScores = new int[hardScores.length];
int[] newSoftScores = new int[softScores.length];
for (int i = 0; i < newHardScores.length; i++) {
@@ -311,7 +303,7 @@ public BendableScore multiply(double multiplicand) {
}
@Override
- public BendableScore divide(double divisor) {
+ public @NonNull BendableScore divide(double divisor) {
int[] newHardScores = new int[hardScores.length];
int[] newSoftScores = new int[softScores.length];
for (int i = 0; i < newHardScores.length; i++) {
@@ -326,7 +318,7 @@ public BendableScore divide(double divisor) {
}
@Override
- public BendableScore power(double exponent) {
+ public @NonNull BendableScore power(double exponent) {
int[] newHardScores = new int[hardScores.length];
int[] newSoftScores = new int[softScores.length];
for (int i = 0; i < newHardScores.length; i++) {
@@ -341,7 +333,7 @@ public BendableScore power(double exponent) {
}
@Override
- public BendableScore negate() { // Overridden as the default impl would create zero() all the time.
+ public @NonNull BendableScore negate() { // Overridden as the default impl would create zero() all the time.
int[] newHardScores = new int[hardScores.length];
int[] newSoftScores = new int[softScores.length];
for (int i = 0; i < newHardScores.length; i++) {
@@ -354,7 +346,7 @@ public BendableScore negate() { // Overridden as the default impl would create z
}
@Override
- public BendableScore abs() {
+ public @NonNull BendableScore abs() {
int[] newHardScores = new int[hardScores.length];
int[] newSoftScores = new int[softScores.length];
for (int i = 0; i < newHardScores.length; i++) {
@@ -367,12 +359,12 @@ public BendableScore abs() {
}
@Override
- public BendableScore zero() {
+ public @NonNull BendableScore zero() {
return BendableScore.zero(hardLevelsSize(), softLevelsSize());
}
@Override
- public Number[] toLevelNumbers() {
+ public Number @NonNull [] toLevelNumbers() {
Number[] levelNumbers = new Number[hardScores.length + softScores.length];
for (int i = 0; i < hardScores.length; i++) {
levelNumbers[i] = hardScores[i];
@@ -414,7 +406,7 @@ public int hashCode() {
}
@Override
- public int compareTo(BendableScore other) {
+ public int compareTo(@NonNull BendableScore other) {
validateCompatible(other);
if (initScore != other.initScore()) {
return Integer.compare(initScore, other.initScore());
@@ -433,7 +425,7 @@ public int compareTo(BendableScore other) {
}
@Override
- public String toShortString() {
+ public @NonNull String toShortString() {
return ScoreUtil.buildBendableShortString(this, n -> n.intValue() != 0);
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/bendablebigdecimal/BendableBigDecimalScore.java b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/bendablebigdecimal/BendableBigDecimalScore.java
index 3b746639de..2b5ba346b7 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/bendablebigdecimal/BendableBigDecimalScore.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/bendablebigdecimal/BendableBigDecimalScore.java
@@ -11,6 +11,8 @@
import ai.timefold.solver.core.impl.score.ScoreUtil;
import ai.timefold.solver.core.impl.score.buildin.BendableScoreDefinition;
+import org.jspecify.annotations.NonNull;
+
/**
* This {@link Score} is based on n levels of {@link BigDecimal} constraints.
* The number of levels is bendable at configuration time.
@@ -24,11 +26,7 @@
*/
public final class BendableBigDecimalScore implements IBendableScore {
- /**
- * @param scoreString never null
- * @return never null
- */
- public static BendableBigDecimalScore parseScore(String scoreString) {
+ public static @NonNull BendableBigDecimalScore parseScore(@NonNull String scoreString) {
String[][] scoreTokens = ScoreUtil.parseBendableScoreTokens(BendableBigDecimalScore.class, scoreString);
int initScore = ScoreUtil.parseInitScore(BendableBigDecimalScore.class, scoreString, scoreTokens[0][0]);
BigDecimal[] hardScores = new BigDecimal[scoreTokens[1].length];
@@ -46,22 +44,21 @@ public static BendableBigDecimalScore parseScore(String scoreString) {
* Creates a new {@link BendableBigDecimalScore}.
*
* @param initScore see {@link Score#initScore()}
- * @param hardScores never null, never change that array afterwards: it must be immutable
- * @param softScores never null, never change that array afterwards: it must be immutable
- * @return never null
+ * @param hardScores never change that array afterwards: it must be immutable
+ * @param softScores never change that array afterwards: it must be immutable
*/
- public static BendableBigDecimalScore ofUninitialized(int initScore, BigDecimal[] hardScores, BigDecimal[] softScores) {
+ public static @NonNull BendableBigDecimalScore ofUninitialized(int initScore, @NonNull BigDecimal @NonNull [] hardScores,
+ @NonNull BigDecimal @NonNull [] softScores) {
return new BendableBigDecimalScore(initScore, hardScores, softScores);
}
/**
* Creates a new {@link BendableBigDecimalScore}.
*
- * @param hardScores never null, never change that array afterwards: it must be immutable
- * @param softScores never null, never change that array afterwards: it must be immutable
- * @return never null
+ * @param hardScores never change that array afterwards: it must be immutable
+ * @param softScores never change that array afterwards: it must be immutable
*/
- public static BendableBigDecimalScore of(BigDecimal[] hardScores, BigDecimal[] softScores) {
+ public static @NonNull BendableBigDecimalScore of(BigDecimal @NonNull [] hardScores, BigDecimal @NonNull [] softScores) {
return new BendableBigDecimalScore(0, hardScores, softScores);
}
@@ -70,9 +67,8 @@ public static BendableBigDecimalScore of(BigDecimal[] hardScores, BigDecimal[] s
*
* @param hardLevelsSize at least 0
* @param softLevelsSize at least 0
- * @return never null
*/
- public static BendableBigDecimalScore zero(int hardLevelsSize, int softLevelsSize) {
+ public static @NonNull BendableBigDecimalScore zero(int hardLevelsSize, int softLevelsSize) {
BigDecimal[] hardScores = new BigDecimal[hardLevelsSize];
Arrays.fill(hardScores, BigDecimal.ZERO);
BigDecimal[] softScores = new BigDecimal[softLevelsSize];
@@ -86,10 +82,9 @@ public static BendableBigDecimalScore zero(int hardLevelsSize, int softLevelsSiz
* @param hardLevelsSize at least 0
* @param softLevelsSize at least 0
* @param hardLevel at least 0, less than hardLevelsSize
- * @param hardScore never null
- * @return never null
*/
- public static BendableBigDecimalScore ofHard(int hardLevelsSize, int softLevelsSize, int hardLevel, BigDecimal hardScore) {
+ public static @NonNull BendableBigDecimalScore ofHard(int hardLevelsSize, int softLevelsSize, int hardLevel,
+ @NonNull BigDecimal hardScore) {
BigDecimal[] hardScores = new BigDecimal[hardLevelsSize];
Arrays.fill(hardScores, BigDecimal.ZERO);
BigDecimal[] softScores = new BigDecimal[softLevelsSize];
@@ -104,10 +99,9 @@ public static BendableBigDecimalScore ofHard(int hardLevelsSize, int softLevelsS
* @param hardLevelsSize at least 0
* @param softLevelsSize at least 0
* @param softLevel at least 0, less than softLevelsSize
- * @param softScore never null
- * @return never null
*/
- public static BendableBigDecimalScore ofSoft(int hardLevelsSize, int softLevelsSize, int softLevel, BigDecimal softScore) {
+ public static @NonNull BendableBigDecimalScore ofSoft(int hardLevelsSize, int softLevelsSize, int softLevel,
+ @NonNull BigDecimal softScore) {
BigDecimal[] hardScores = new BigDecimal[hardLevelsSize];
Arrays.fill(hardScores, BigDecimal.ZERO);
BigDecimal[] softScores = new BigDecimal[softLevelsSize];
@@ -121,8 +115,8 @@ public static BendableBigDecimalScore ofSoft(int hardLevelsSize, int softLevelsS
// ************************************************************************
private final int initScore;
- private final BigDecimal[] hardScores;
- private final BigDecimal[] softScores;
+ private final @NonNull BigDecimal @NonNull [] hardScores;
+ private final @NonNull BigDecimal @NonNull [] softScores;
/**
* Private default constructor for default marshalling/unmarshalling of unknown frameworks that use reflection.
@@ -131,15 +125,14 @@ public static BendableBigDecimalScore ofSoft(int hardLevelsSize, int softLevelsS
*/
@SuppressWarnings("unused")
private BendableBigDecimalScore() {
- this(Integer.MIN_VALUE, null, null);
+ this(Integer.MIN_VALUE, new BigDecimal[] {}, new BigDecimal[] {});
}
/**
* @param initScore see {@link Score#initScore()}
- * @param hardScores never null
- * @param softScores never null
*/
- private BendableBigDecimalScore(int initScore, BigDecimal[] hardScores, BigDecimal[] softScores) {
+ private BendableBigDecimalScore(int initScore, @NonNull BigDecimal @NonNull [] hardScores,
+ @NonNull BigDecimal @NonNull [] softScores) {
this.initScore = initScore;
this.hardScores = hardScores;
this.softScores = softScores;
@@ -151,9 +144,9 @@ public int initScore() {
}
/**
- * @return not null, array copy because this class is immutable
+ * @return array copy because this class is immutable
*/
- public BigDecimal[] hardScores() {
+ public @NonNull BigDecimal @NonNull [] hardScores() {
return Arrays.copyOf(hardScores, hardScores.length);
}
@@ -163,14 +156,14 @@ public BigDecimal[] hardScores() {
* @deprecated Use {@link #hardScores()} instead.
*/
@Deprecated(forRemoval = true)
- public BigDecimal[] getHardScores() {
+ public @NonNull BigDecimal @NonNull [] getHardScores() {
return hardScores();
}
/**
- * @return not null, array copy because this class is immutable
+ * @return array copy because this class is immutable
*/
- public BigDecimal[] softScores() {
+ public @NonNull BigDecimal @NonNull [] softScores() {
return Arrays.copyOf(softScores, softScores.length);
}
@@ -180,7 +173,7 @@ public BigDecimal[] softScores() {
* @deprecated Use {@link #softScores()} instead.
*/
@Deprecated(forRemoval = true)
- public BigDecimal[] getSoftScores() {
+ public @NonNull BigDecimal @NonNull [] getSoftScores() {
return softScores();
}
@@ -193,7 +186,7 @@ public int hardLevelsSize() {
* @param index {@code 0 <= index <} {@link #hardLevelsSize()}
* @return higher is better
*/
- public BigDecimal hardScore(int index) {
+ public @NonNull BigDecimal hardScore(int index) {
return hardScores[index];
}
@@ -203,7 +196,7 @@ public BigDecimal hardScore(int index) {
* @deprecated Use {@link #hardScore(int)} instead.
*/
@Deprecated(forRemoval = true)
- public BigDecimal getHardScore(int index) {
+ public @NonNull BigDecimal getHardScore(int index) {
return hardScore(index);
}
@@ -216,7 +209,7 @@ public int softLevelsSize() {
* @param index {@code 0 <= index <} {@link #softLevelsSize()}
* @return higher is better
*/
- public BigDecimal softScore(int index) {
+ public @NonNull BigDecimal softScore(int index) {
return softScores[index];
}
@@ -226,7 +219,7 @@ public BigDecimal softScore(int index) {
* @deprecated Use {@link #softScore(int)} instead.
*/
@Deprecated(forRemoval = true)
- public BigDecimal getSoftScore(int index) {
+ public @NonNull BigDecimal getSoftScore(int index) {
return softScore(index);
}
@@ -235,7 +228,7 @@ public BigDecimal getSoftScore(int index) {
// ************************************************************************
@Override
- public BendableBigDecimalScore withInitScore(int newInitScore) {
+ public @NonNull BendableBigDecimalScore withInitScore(int newInitScore) {
return new BendableBigDecimalScore(newInitScore, hardScores, softScores);
}
@@ -243,7 +236,7 @@ public BendableBigDecimalScore withInitScore(int newInitScore) {
* @param index {@code 0 <= index <} {@link #levelsSize()}
* @return higher is better
*/
- public BigDecimal hardOrSoftScore(int index) {
+ public @NonNull BigDecimal hardOrSoftScore(int index) {
if (index < hardScores.length) {
return hardScores[index];
} else {
@@ -257,7 +250,7 @@ public BigDecimal hardOrSoftScore(int index) {
* @deprecated Use {@link #hardOrSoftScore(int)} instead.
*/
@Deprecated(forRemoval = true)
- public BigDecimal getHardOrSoftScore(int index) {
+ public @NonNull BigDecimal getHardOrSoftScore(int index) {
return hardOrSoftScore(index);
}
@@ -275,7 +268,7 @@ public boolean isFeasible() {
}
@Override
- public BendableBigDecimalScore add(BendableBigDecimalScore addend) {
+ public @NonNull BendableBigDecimalScore add(@NonNull BendableBigDecimalScore addend) {
validateCompatible(addend);
BigDecimal[] newHardScores = new BigDecimal[hardScores.length];
BigDecimal[] newSoftScores = new BigDecimal[softScores.length];
@@ -291,7 +284,7 @@ public BendableBigDecimalScore add(BendableBigDecimalScore addend) {
}
@Override
- public BendableBigDecimalScore subtract(BendableBigDecimalScore subtrahend) {
+ public @NonNull BendableBigDecimalScore subtract(@NonNull BendableBigDecimalScore subtrahend) {
validateCompatible(subtrahend);
BigDecimal[] newHardScores = new BigDecimal[hardScores.length];
BigDecimal[] newSoftScores = new BigDecimal[softScores.length];
@@ -307,7 +300,7 @@ public BendableBigDecimalScore subtract(BendableBigDecimalScore subtrahend) {
}
@Override
- public BendableBigDecimalScore multiply(double multiplicand) {
+ public @NonNull BendableBigDecimalScore multiply(double multiplicand) {
BigDecimal[] newHardScores = new BigDecimal[hardScores.length];
BigDecimal[] newSoftScores = new BigDecimal[softScores.length];
BigDecimal bigDecimalMultiplicand = BigDecimal.valueOf(multiplicand);
@@ -327,7 +320,7 @@ public BendableBigDecimalScore multiply(double multiplicand) {
}
@Override
- public BendableBigDecimalScore divide(double divisor) {
+ public @NonNull BendableBigDecimalScore divide(double divisor) {
BigDecimal[] newHardScores = new BigDecimal[hardScores.length];
BigDecimal[] newSoftScores = new BigDecimal[softScores.length];
BigDecimal bigDecimalDivisor = BigDecimal.valueOf(divisor);
@@ -345,7 +338,7 @@ public BendableBigDecimalScore divide(double divisor) {
}
@Override
- public BendableBigDecimalScore power(double exponent) {
+ public @NonNull BendableBigDecimalScore power(double exponent) {
BigDecimal[] newHardScores = new BigDecimal[hardScores.length];
BigDecimal[] newSoftScores = new BigDecimal[softScores.length];
BigDecimal actualExponent = BigDecimal.valueOf(exponent);
@@ -366,7 +359,7 @@ public BendableBigDecimalScore power(double exponent) {
}
@Override
- public BendableBigDecimalScore negate() { // Overridden as the default impl would create zero() all the time.
+ public @NonNull BendableBigDecimalScore negate() { // Overridden as the default impl would create zero() all the time.
BigDecimal[] newHardScores = new BigDecimal[hardScores.length];
BigDecimal[] newSoftScores = new BigDecimal[softScores.length];
for (int i = 0; i < newHardScores.length; i++) {
@@ -379,7 +372,7 @@ public BendableBigDecimalScore negate() { // Overridden as the default impl woul
}
@Override
- public BendableBigDecimalScore abs() {
+ public @NonNull BendableBigDecimalScore abs() {
BigDecimal[] newHardScores = new BigDecimal[hardScores.length];
BigDecimal[] newSoftScores = new BigDecimal[softScores.length];
for (int i = 0; i < newHardScores.length; i++) {
@@ -392,12 +385,12 @@ public BendableBigDecimalScore abs() {
}
@Override
- public BendableBigDecimalScore zero() {
+ public @NonNull BendableBigDecimalScore zero() {
return BendableBigDecimalScore.zero(hardLevelsSize(), softLevelsSize());
}
@Override
- public Number[] toLevelNumbers() {
+ public @NonNull Number @NonNull [] toLevelNumbers() {
Number[] levelNumbers = new Number[hardScores.length + softScores.length];
for (int i = 0; i < hardScores.length; i++) {
levelNumbers[i] = hardScores[i];
@@ -443,7 +436,7 @@ public int hashCode() {
}
@Override
- public int compareTo(BendableBigDecimalScore other) {
+ public int compareTo(@NonNull BendableBigDecimalScore other) {
validateCompatible(other);
if (initScore != other.initScore()) {
return Integer.compare(initScore, other.initScore());
@@ -464,7 +457,7 @@ public int compareTo(BendableBigDecimalScore other) {
}
@Override
- public String toShortString() {
+ public @NonNull String toShortString() {
return ScoreUtil.buildBendableShortString(this, n -> ((BigDecimal) n).compareTo(BigDecimal.ZERO) != 0);
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/bendablelong/BendableLongScore.java b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/bendablelong/BendableLongScore.java
index d73dd6482d..f26b2398c9 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/bendablelong/BendableLongScore.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/bendablelong/BendableLongScore.java
@@ -8,6 +8,8 @@
import ai.timefold.solver.core.impl.score.ScoreUtil;
import ai.timefold.solver.core.impl.score.buildin.BendableLongScoreDefinition;
+import org.jspecify.annotations.NonNull;
+
/**
* This {@link Score} is based on n levels of long constraints.
* The number of levels is bendable at configuration time.
@@ -21,11 +23,7 @@
*/
public final class BendableLongScore implements IBendableScore {
- /**
- * @param scoreString never null
- * @return never null
- */
- public static BendableLongScore parseScore(String scoreString) {
+ public static @NonNull BendableLongScore parseScore(@NonNull String scoreString) {
String[][] scoreTokens = ScoreUtil.parseBendableScoreTokens(BendableLongScore.class, scoreString);
int initScore = ScoreUtil.parseInitScore(BendableLongScore.class, scoreString, scoreTokens[0][0]);
long[] hardScores = new long[scoreTokens[1].length];
@@ -43,22 +41,21 @@ public static BendableLongScore parseScore(String scoreString) {
* Creates a new {@link BendableLongScore}.
*
* @param initScore see {@link Score#initScore()}
- * @param hardScores never null, never change that array afterwards: it must be immutable
- * @param softScores never null, never change that array afterwards: it must be immutable
- * @return never null
+ * @param hardScores never change that array afterwards: it must be immutable
+ * @param softScores never change that array afterwards: it must be immutable
*/
- public static BendableLongScore ofUninitialized(int initScore, long[] hardScores, long[] softScores) {
+ public static @NonNull BendableLongScore ofUninitialized(int initScore, long @NonNull [] hardScores,
+ long @NonNull [] softScores) {
return new BendableLongScore(initScore, hardScores, softScores);
}
/**
* Creates a new {@link BendableLongScore}.
*
- * @param hardScores never null, never change that array afterwards: it must be immutable
- * @param softScores never null, never change that array afterwards: it must be immutable
- * @return never null
+ * @param hardScores never change that array afterwards: it must be immutable
+ * @param softScores never change that array afterwards: it must be immutable
*/
- public static BendableLongScore of(long[] hardScores, long[] softScores) {
+ public static @NonNull BendableLongScore of(long @NonNull [] hardScores, long @NonNull [] softScores) {
return new BendableLongScore(0, hardScores, softScores);
}
@@ -67,9 +64,8 @@ public static BendableLongScore of(long[] hardScores, long[] softScores) {
*
* @param hardLevelsSize at least 0
* @param softLevelsSize at least 0
- * @return never null
*/
- public static BendableLongScore zero(int hardLevelsSize, int softLevelsSize) {
+ public static @NonNull BendableLongScore zero(int hardLevelsSize, int softLevelsSize) {
return new BendableLongScore(0, new long[hardLevelsSize], new long[softLevelsSize]);
}
@@ -80,9 +76,8 @@ public static BendableLongScore zero(int hardLevelsSize, int softLevelsSize) {
* @param softLevelsSize at least 0
* @param hardLevel at least 0, less than hardLevelsSize
* @param hardScore any
- * @return never null
*/
- public static BendableLongScore ofHard(int hardLevelsSize, int softLevelsSize, int hardLevel, long hardScore) {
+ public static @NonNull BendableLongScore ofHard(int hardLevelsSize, int softLevelsSize, int hardLevel, long hardScore) {
long[] hardScores = new long[hardLevelsSize];
hardScores[hardLevel] = hardScore;
return new BendableLongScore(0, hardScores, new long[softLevelsSize]);
@@ -95,9 +90,8 @@ public static BendableLongScore ofHard(int hardLevelsSize, int softLevelsSize, i
* @param softLevelsSize at least 0
* @param softLevel at least 0, less than softLevelsSize
* @param softScore any
- * @return never null
*/
- public static BendableLongScore ofSoft(int hardLevelsSize, int softLevelsSize, int softLevel, long softScore) {
+ public static @NonNull BendableLongScore ofSoft(int hardLevelsSize, int softLevelsSize, int softLevel, long softScore) {
long[] softScores = new long[softLevelsSize];
softScores[softLevel] = softScore;
return new BendableLongScore(0, new long[hardLevelsSize], softScores);
@@ -118,15 +112,13 @@ public static BendableLongScore ofSoft(int hardLevelsSize, int softLevelsSize, i
*/
@SuppressWarnings("unused")
private BendableLongScore() {
- this(Integer.MIN_VALUE, null, null);
+ this(Integer.MIN_VALUE, new long[] {}, new long[] {});
}
/**
* @param initScore see {@link Score#initScore()}
- * @param hardScores never null
- * @param softScores never null
*/
- private BendableLongScore(int initScore, long[] hardScores, long[] softScores) {
+ private BendableLongScore(int initScore, long @NonNull [] hardScores, long @NonNull [] softScores) {
this.initScore = initScore;
this.hardScores = hardScores;
this.softScores = softScores;
@@ -138,9 +130,9 @@ public int initScore() {
}
/**
- * @return not null, array copy because this class is immutable
+ * @return array copy because this class is immutable
*/
- public long[] hardScores() {
+ public long @NonNull [] hardScores() {
return Arrays.copyOf(hardScores, hardScores.length);
}
@@ -150,14 +142,14 @@ public long[] hardScores() {
* @deprecated Use {@link #hardScores()} instead.
*/
@Deprecated(forRemoval = true)
- public long[] getHardScores() {
+ public long @NonNull [] getHardScores() {
return hardScores();
}
/**
- * @return not null, array copy because this class is immutable
+ * @return array copy because this class is immutable
*/
- public long[] softScores() {
+ public long @NonNull [] softScores() {
return Arrays.copyOf(softScores, softScores.length);
}
@@ -167,7 +159,7 @@ public long[] softScores() {
* @deprecated Use {@link #softScores()} instead.
*/
@Deprecated(forRemoval = true)
- public long[] getSoftScores() {
+ public long @NonNull [] getSoftScores() {
return softScores();
}
@@ -222,7 +214,7 @@ public long getSoftScore(int index) {
// ************************************************************************
@Override
- public BendableLongScore withInitScore(int newInitScore) {
+ public @NonNull BendableLongScore withInitScore(int newInitScore) {
return new BendableLongScore(newInitScore, hardScores, softScores);
}
@@ -262,7 +254,7 @@ public boolean isFeasible() {
}
@Override
- public BendableLongScore add(BendableLongScore addend) {
+ public @NonNull BendableLongScore add(@NonNull BendableLongScore addend) {
validateCompatible(addend);
long[] newHardScores = new long[hardScores.length];
long[] newSoftScores = new long[softScores.length];
@@ -278,7 +270,7 @@ public BendableLongScore add(BendableLongScore addend) {
}
@Override
- public BendableLongScore subtract(BendableLongScore subtrahend) {
+ public @NonNull BendableLongScore subtract(@NonNull BendableLongScore subtrahend) {
validateCompatible(subtrahend);
long[] newHardScores = new long[hardScores.length];
long[] newSoftScores = new long[softScores.length];
@@ -294,7 +286,7 @@ public BendableLongScore subtract(BendableLongScore subtrahend) {
}
@Override
- public BendableLongScore multiply(double multiplicand) {
+ public @NonNull BendableLongScore multiply(double multiplicand) {
long[] newHardScores = new long[hardScores.length];
long[] newSoftScores = new long[softScores.length];
for (int i = 0; i < newHardScores.length; i++) {
@@ -309,7 +301,7 @@ public BendableLongScore multiply(double multiplicand) {
}
@Override
- public BendableLongScore divide(double divisor) {
+ public @NonNull BendableLongScore divide(double divisor) {
long[] newHardScores = new long[hardScores.length];
long[] newSoftScores = new long[softScores.length];
for (int i = 0; i < newHardScores.length; i++) {
@@ -324,7 +316,7 @@ public BendableLongScore divide(double divisor) {
}
@Override
- public BendableLongScore power(double exponent) {
+ public @NonNull BendableLongScore power(double exponent) {
long[] newHardScores = new long[hardScores.length];
long[] newSoftScores = new long[softScores.length];
for (int i = 0; i < newHardScores.length; i++) {
@@ -339,7 +331,7 @@ public BendableLongScore power(double exponent) {
}
@Override
- public BendableLongScore negate() { // Overridden as the default impl would create zero() all the time.
+ public @NonNull BendableLongScore negate() { // Overridden as the default impl would create zero() all the time.
long[] newHardScores = new long[hardScores.length];
long[] newSoftScores = new long[softScores.length];
for (int i = 0; i < newHardScores.length; i++) {
@@ -352,7 +344,7 @@ public BendableLongScore negate() { // Overridden as the default impl would crea
}
@Override
- public BendableLongScore abs() {
+ public @NonNull BendableLongScore abs() {
long[] newHardScores = new long[hardScores.length];
long[] newSoftScores = new long[softScores.length];
for (int i = 0; i < newHardScores.length; i++) {
@@ -365,12 +357,12 @@ public BendableLongScore abs() {
}
@Override
- public BendableLongScore zero() {
+ public @NonNull BendableLongScore zero() {
return BendableLongScore.zero(hardLevelsSize(), softLevelsSize());
}
@Override
- public Number[] toLevelNumbers() {
+ public Number @NonNull [] toLevelNumbers() {
Number[] levelNumbers = new Number[hardScores.length + softScores.length];
for (int i = 0; i < hardScores.length; i++) {
levelNumbers[i] = hardScores[i];
@@ -412,7 +404,7 @@ public int hashCode() {
}
@Override
- public int compareTo(BendableLongScore other) {
+ public int compareTo(@NonNull BendableLongScore other) {
validateCompatible(other);
if (initScore != other.initScore()) {
return Integer.compare(initScore, other.initScore());
@@ -431,7 +423,7 @@ public int compareTo(BendableLongScore other) {
}
@Override
- public String toShortString() {
+ public @NonNull String toShortString() {
return ScoreUtil.buildBendableShortString(this, n -> n.longValue() != 0L);
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardmediumsoft/HardMediumSoftScore.java b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardmediumsoft/HardMediumSoftScore.java
index fa7b255d9e..08a704b0b7 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardmediumsoft/HardMediumSoftScore.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardmediumsoft/HardMediumSoftScore.java
@@ -10,6 +10,8 @@
import ai.timefold.solver.core.api.score.Score;
import ai.timefold.solver.core.impl.score.ScoreUtil;
+import org.jspecify.annotations.NonNull;
+
/**
* This {@link Score} is based on 3 levels of int constraints: hard, medium and soft.
* Hard constraints have priority over medium constraints.
@@ -22,15 +24,15 @@
*/
public final class HardMediumSoftScore implements Score {
- public static final HardMediumSoftScore ZERO = new HardMediumSoftScore(0, 0, 0, 0);
- public static final HardMediumSoftScore ONE_HARD = new HardMediumSoftScore(0, 1, 0, 0);
- private static final HardMediumSoftScore MINUS_ONE_HARD = new HardMediumSoftScore(0, -1, 0, 0);
- public static final HardMediumSoftScore ONE_MEDIUM = new HardMediumSoftScore(0, 0, 1, 0);
- private static final HardMediumSoftScore MINUS_ONE_MEDIUM = new HardMediumSoftScore(0, 0, -1, 0);
- public static final HardMediumSoftScore ONE_SOFT = new HardMediumSoftScore(0, 0, 0, 1);
- private static final HardMediumSoftScore MINUS_ONE_SOFT = new HardMediumSoftScore(0, 0, 0, -1);
+ public static final @NonNull HardMediumSoftScore ZERO = new HardMediumSoftScore(0, 0, 0, 0);
+ public static final @NonNull HardMediumSoftScore ONE_HARD = new HardMediumSoftScore(0, 1, 0, 0);
+ private static final @NonNull HardMediumSoftScore MINUS_ONE_HARD = new HardMediumSoftScore(0, -1, 0, 0);
+ public static final @NonNull HardMediumSoftScore ONE_MEDIUM = new HardMediumSoftScore(0, 0, 1, 0);
+ private static final @NonNull HardMediumSoftScore MINUS_ONE_MEDIUM = new HardMediumSoftScore(0, 0, -1, 0);
+ public static final @NonNull HardMediumSoftScore ONE_SOFT = new HardMediumSoftScore(0, 0, 0, 1);
+ private static final @NonNull HardMediumSoftScore MINUS_ONE_SOFT = new HardMediumSoftScore(0, 0, 0, -1);
- public static HardMediumSoftScore parseScore(String scoreString) {
+ public static @NonNull HardMediumSoftScore parseScore(@NonNull String scoreString) {
String[] scoreTokens = ScoreUtil.parseScoreTokens(HardMediumSoftScore.class, scoreString,
HARD_LABEL, MEDIUM_LABEL, SOFT_LABEL);
int initScore = ScoreUtil.parseInitScore(HardMediumSoftScore.class, scoreString, scoreTokens[0]);
@@ -40,14 +42,14 @@ public static HardMediumSoftScore parseScore(String scoreString) {
return ofUninitialized(initScore, hardScore, mediumScore, softScore);
}
- public static HardMediumSoftScore ofUninitialized(int initScore, int hardScore, int mediumScore, int softScore) {
+ public static @NonNull HardMediumSoftScore ofUninitialized(int initScore, int hardScore, int mediumScore, int softScore) {
if (initScore == 0) {
return of(hardScore, mediumScore, softScore);
}
return new HardMediumSoftScore(initScore, hardScore, mediumScore, softScore);
}
- public static HardMediumSoftScore of(int hardScore, int mediumScore, int softScore) {
+ public static @NonNull HardMediumSoftScore of(int hardScore, int mediumScore, int softScore) {
if (hardScore == -1 && mediumScore == 0 && softScore == 0) {
return MINUS_ONE_HARD;
} else if (hardScore == 0) {
@@ -70,7 +72,7 @@ public static HardMediumSoftScore of(int hardScore, int mediumScore, int softSco
return new HardMediumSoftScore(0, hardScore, mediumScore, softScore);
}
- public static HardMediumSoftScore ofHard(int hardScore) {
+ public static @NonNull HardMediumSoftScore ofHard(int hardScore) {
return switch (hardScore) {
case -1 -> MINUS_ONE_HARD;
case 0 -> ZERO;
@@ -79,7 +81,7 @@ public static HardMediumSoftScore ofHard(int hardScore) {
};
}
- public static HardMediumSoftScore ofMedium(int mediumScore) {
+ public static @NonNull HardMediumSoftScore ofMedium(int mediumScore) {
return switch (mediumScore) {
case -1 -> MINUS_ONE_MEDIUM;
case 0 -> ZERO;
@@ -88,7 +90,7 @@ public static HardMediumSoftScore ofMedium(int mediumScore) {
};
}
- public static HardMediumSoftScore ofSoft(int softScore) {
+ public static @NonNull HardMediumSoftScore ofSoft(int softScore) {
return switch (softScore) {
case -1 -> MINUS_ONE_SOFT;
case 0 -> ZERO;
@@ -200,7 +202,7 @@ public int getSoftScore() {
// ************************************************************************
@Override
- public HardMediumSoftScore withInitScore(int newInitScore) {
+ public @NonNull HardMediumSoftScore withInitScore(int newInitScore) {
return ofUninitialized(newInitScore, hardScore, mediumScore, softScore);
}
@@ -215,7 +217,7 @@ public boolean isFeasible() {
}
@Override
- public HardMediumSoftScore add(HardMediumSoftScore addend) {
+ public @NonNull HardMediumSoftScore add(@NonNull HardMediumSoftScore addend) {
return ofUninitialized(
initScore + addend.initScore(),
hardScore + addend.hardScore(),
@@ -224,7 +226,7 @@ public HardMediumSoftScore add(HardMediumSoftScore addend) {
}
@Override
- public HardMediumSoftScore subtract(HardMediumSoftScore subtrahend) {
+ public @NonNull HardMediumSoftScore subtract(@NonNull HardMediumSoftScore subtrahend) {
return ofUninitialized(
initScore - subtrahend.initScore(),
hardScore - subtrahend.hardScore(),
@@ -233,7 +235,7 @@ public HardMediumSoftScore subtract(HardMediumSoftScore subtrahend) {
}
@Override
- public HardMediumSoftScore multiply(double multiplicand) {
+ public @NonNull HardMediumSoftScore multiply(double multiplicand) {
return ofUninitialized(
(int) Math.floor(initScore * multiplicand),
(int) Math.floor(hardScore * multiplicand),
@@ -242,7 +244,7 @@ public HardMediumSoftScore multiply(double multiplicand) {
}
@Override
- public HardMediumSoftScore divide(double divisor) {
+ public @NonNull HardMediumSoftScore divide(double divisor) {
return ofUninitialized(
(int) Math.floor(initScore / divisor),
(int) Math.floor(hardScore / divisor),
@@ -251,7 +253,7 @@ public HardMediumSoftScore divide(double divisor) {
}
@Override
- public HardMediumSoftScore power(double exponent) {
+ public @NonNull HardMediumSoftScore power(double exponent) {
return ofUninitialized(
(int) Math.floor(Math.pow(initScore, exponent)),
(int) Math.floor(Math.pow(hardScore, exponent)),
@@ -260,17 +262,17 @@ public HardMediumSoftScore power(double exponent) {
}
@Override
- public HardMediumSoftScore abs() {
+ public @NonNull HardMediumSoftScore abs() {
return ofUninitialized(Math.abs(initScore), Math.abs(hardScore), Math.abs(mediumScore), Math.abs(softScore));
}
@Override
- public HardMediumSoftScore zero() {
+ public @NonNull HardMediumSoftScore zero() {
return HardMediumSoftScore.ZERO;
}
@Override
- public Number[] toLevelNumbers() {
+ public Number @NonNull [] toLevelNumbers() {
return new Number[] { hardScore, mediumScore, softScore };
}
@@ -291,7 +293,7 @@ public int hashCode() {
}
@Override
- public int compareTo(HardMediumSoftScore other) {
+ public int compareTo(@NonNull HardMediumSoftScore other) {
if (initScore != other.initScore()) {
return Integer.compare(initScore, other.initScore());
} else if (hardScore != other.hardScore()) {
@@ -304,7 +306,7 @@ public int compareTo(HardMediumSoftScore other) {
}
@Override
- public String toShortString() {
+ public @NonNull String toShortString() {
return ScoreUtil.buildShortString(this, n -> n.intValue() != 0, HARD_LABEL, MEDIUM_LABEL, SOFT_LABEL);
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardmediumsoftbigdecimal/HardMediumSoftBigDecimalScore.java b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardmediumsoftbigdecimal/HardMediumSoftBigDecimalScore.java
index 51d63db2a4..977491beb8 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardmediumsoftbigdecimal/HardMediumSoftBigDecimalScore.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardmediumsoftbigdecimal/HardMediumSoftBigDecimalScore.java
@@ -12,6 +12,8 @@
import ai.timefold.solver.core.api.score.Score;
import ai.timefold.solver.core.impl.score.ScoreUtil;
+import org.jspecify.annotations.NonNull;
+
/**
* This {@link Score} is based on 3 levels of {@link BigDecimal} constraints: hard, medium and soft.
* Hard constraints have priority over medium constraints.
@@ -24,23 +26,25 @@
*/
public final class HardMediumSoftBigDecimalScore implements Score {
- public static final HardMediumSoftBigDecimalScore ZERO = new HardMediumSoftBigDecimalScore(0, BigDecimal.ZERO,
+ public static final @NonNull HardMediumSoftBigDecimalScore ZERO = new HardMediumSoftBigDecimalScore(0, BigDecimal.ZERO,
BigDecimal.ZERO, BigDecimal.ZERO);
- public static final HardMediumSoftBigDecimalScore ONE_HARD = new HardMediumSoftBigDecimalScore(0, BigDecimal.ONE,
+ public static final @NonNull HardMediumSoftBigDecimalScore ONE_HARD = new HardMediumSoftBigDecimalScore(0, BigDecimal.ONE,
BigDecimal.ZERO, BigDecimal.ZERO);
- private static final HardMediumSoftBigDecimalScore MINUS_ONE_HARD =
+ private static final @NonNull HardMediumSoftBigDecimalScore MINUS_ONE_HARD =
new HardMediumSoftBigDecimalScore(0, BigDecimal.ONE.negate(),
BigDecimal.ZERO, BigDecimal.ZERO);
- public static final HardMediumSoftBigDecimalScore ONE_MEDIUM = new HardMediumSoftBigDecimalScore(0, BigDecimal.ZERO,
- BigDecimal.ONE, BigDecimal.ZERO);
- private static final HardMediumSoftBigDecimalScore MINUS_ONE_MEDIUM = new HardMediumSoftBigDecimalScore(0, BigDecimal.ZERO,
- BigDecimal.ONE.negate(), BigDecimal.ZERO);
- public static final HardMediumSoftBigDecimalScore ONE_SOFT = new HardMediumSoftBigDecimalScore(0, BigDecimal.ZERO,
+ public static final @NonNull HardMediumSoftBigDecimalScore ONE_MEDIUM =
+ new HardMediumSoftBigDecimalScore(0, BigDecimal.ZERO,
+ BigDecimal.ONE, BigDecimal.ZERO);
+ private static final @NonNull HardMediumSoftBigDecimalScore MINUS_ONE_MEDIUM =
+ new HardMediumSoftBigDecimalScore(0, BigDecimal.ZERO,
+ BigDecimal.ONE.negate(), BigDecimal.ZERO);
+ public static final @NonNull HardMediumSoftBigDecimalScore ONE_SOFT = new HardMediumSoftBigDecimalScore(0, BigDecimal.ZERO,
BigDecimal.ZERO, BigDecimal.ONE);
- private static final HardMediumSoftBigDecimalScore MINUS_ONE_SOFT =
+ private static final @NonNull HardMediumSoftBigDecimalScore MINUS_ONE_SOFT =
new HardMediumSoftBigDecimalScore(0, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ONE.negate());
- public static HardMediumSoftBigDecimalScore parseScore(String scoreString) {
+ public static @NonNull HardMediumSoftBigDecimalScore parseScore(@NonNull String scoreString) {
String[] scoreTokens = ScoreUtil.parseScoreTokens(HardMediumSoftBigDecimalScore.class, scoreString,
HARD_LABEL, MEDIUM_LABEL, SOFT_LABEL);
int initScore = ScoreUtil.parseInitScore(HardMediumSoftBigDecimalScore.class, scoreString, scoreTokens[0]);
@@ -53,15 +57,17 @@ public static HardMediumSoftBigDecimalScore parseScore(String scoreString) {
return ofUninitialized(initScore, hardScore, mediumScore, softScore);
}
- public static HardMediumSoftBigDecimalScore ofUninitialized(int initScore, BigDecimal hardScore, BigDecimal mediumScore,
- BigDecimal softScore) {
+ public static @NonNull HardMediumSoftBigDecimalScore ofUninitialized(int initScore, @NonNull BigDecimal hardScore,
+ @NonNull BigDecimal mediumScore,
+ @NonNull BigDecimal softScore) {
if (initScore == 0) {
return of(hardScore, mediumScore, softScore);
}
return new HardMediumSoftBigDecimalScore(initScore, hardScore, mediumScore, softScore);
}
- public static HardMediumSoftBigDecimalScore of(BigDecimal hardScore, BigDecimal mediumScore, BigDecimal softScore) {
+ public static @NonNull HardMediumSoftBigDecimalScore of(@NonNull BigDecimal hardScore, @NonNull BigDecimal mediumScore,
+ @NonNull BigDecimal softScore) {
if (Objects.equals(hardScore, BigDecimal.ONE.negate()) && mediumScore.signum() == 0 && softScore.signum() == 0) {
return MINUS_ONE_HARD;
} else if (hardScore.signum() == 0) {
@@ -84,7 +90,7 @@ public static HardMediumSoftBigDecimalScore of(BigDecimal hardScore, BigDecimal
return new HardMediumSoftBigDecimalScore(0, hardScore, mediumScore, softScore);
}
- public static HardMediumSoftBigDecimalScore ofHard(BigDecimal hardScore) {
+ public static @NonNull HardMediumSoftBigDecimalScore ofHard(@NonNull BigDecimal hardScore) {
if (Objects.equals(hardScore, BigDecimal.ONE.negate())) {
return MINUS_ONE_HARD;
} else if (hardScore.signum() == 0) {
@@ -95,7 +101,7 @@ public static HardMediumSoftBigDecimalScore ofHard(BigDecimal hardScore) {
return new HardMediumSoftBigDecimalScore(0, hardScore, BigDecimal.ZERO, BigDecimal.ZERO);
}
- public static HardMediumSoftBigDecimalScore ofMedium(BigDecimal mediumScore) {
+ public static @NonNull HardMediumSoftBigDecimalScore ofMedium(@NonNull BigDecimal mediumScore) {
if (Objects.equals(mediumScore, BigDecimal.ONE.negate())) {
return MINUS_ONE_MEDIUM;
} else if (mediumScore.signum() == 0) {
@@ -106,7 +112,7 @@ public static HardMediumSoftBigDecimalScore ofMedium(BigDecimal mediumScore) {
return new HardMediumSoftBigDecimalScore(0, BigDecimal.ZERO, mediumScore, BigDecimal.ZERO);
}
- public static HardMediumSoftBigDecimalScore ofSoft(BigDecimal softScore) {
+ public static @NonNull HardMediumSoftBigDecimalScore ofSoft(@NonNull BigDecimal softScore) {
if (Objects.equals(softScore, BigDecimal.ONE.negate())) {
return MINUS_ONE_SOFT;
} else if (softScore.signum() == 0) {
@@ -122,9 +128,9 @@ public static HardMediumSoftBigDecimalScore ofSoft(BigDecimal softScore) {
// ************************************************************************
private final int initScore;
- private final BigDecimal hardScore;
- private final BigDecimal mediumScore;
- private final BigDecimal softScore;
+ private final @NonNull BigDecimal hardScore;
+ private final @NonNull BigDecimal mediumScore;
+ private final @NonNull BigDecimal softScore;
/**
* Private default constructor for default marshalling/unmarshalling of unknown frameworks that use reflection.
@@ -133,10 +139,11 @@ public static HardMediumSoftBigDecimalScore ofSoft(BigDecimal softScore) {
*/
@SuppressWarnings("unused")
private HardMediumSoftBigDecimalScore() {
- this(Integer.MIN_VALUE, null, null, null);
+ this(Integer.MIN_VALUE, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO);
}
- private HardMediumSoftBigDecimalScore(int initScore, BigDecimal hardScore, BigDecimal mediumScore, BigDecimal softScore) {
+ private HardMediumSoftBigDecimalScore(int initScore, @NonNull BigDecimal hardScore, @NonNull BigDecimal mediumScore,
+ @NonNull BigDecimal softScore) {
this.initScore = initScore;
this.hardScore = hardScore;
this.mediumScore = mediumScore;
@@ -155,7 +162,7 @@ public int initScore() {
*
* @return higher is better, usually negative, 0 if no hard constraints are broken/fulfilled
*/
- public BigDecimal hardScore() {
+ public @NonNull BigDecimal hardScore() {
return hardScore;
}
@@ -165,7 +172,7 @@ public BigDecimal hardScore() {
* @deprecated Use {@link #hardScore()} instead.
*/
@Deprecated(forRemoval = true)
- public BigDecimal getHardScore() {
+ public @NonNull BigDecimal getHardScore() {
return hardScore;
}
@@ -178,7 +185,7 @@ public BigDecimal getHardScore() {
*
* @return higher is better, usually negative, 0 if no medium constraints are broken/fulfilled
*/
- public BigDecimal mediumScore() {
+ public @NonNull BigDecimal mediumScore() {
return mediumScore;
}
@@ -188,7 +195,7 @@ public BigDecimal mediumScore() {
* @deprecated Use {@link #mediumScore()} instead.
*/
@Deprecated(forRemoval = true)
- public BigDecimal getMediumScore() {
+ public @NonNull BigDecimal getMediumScore() {
return mediumScore;
}
@@ -201,7 +208,7 @@ public BigDecimal getMediumScore() {
*
* @return higher is better, usually negative, 0 if no soft constraints are broken/fulfilled
*/
- public BigDecimal softScore() {
+ public @NonNull BigDecimal softScore() {
return softScore;
}
@@ -211,7 +218,7 @@ public BigDecimal softScore() {
* @deprecated Use {@link #softScore()} instead.
*/
@Deprecated(forRemoval = true)
- public BigDecimal getSoftScore() {
+ public @NonNull BigDecimal getSoftScore() {
return softScore;
}
@@ -220,7 +227,7 @@ public BigDecimal getSoftScore() {
// ************************************************************************
@Override
- public HardMediumSoftBigDecimalScore withInitScore(int newInitScore) {
+ public @NonNull HardMediumSoftBigDecimalScore withInitScore(int newInitScore) {
return ofUninitialized(newInitScore, hardScore, mediumScore, softScore);
}
@@ -235,7 +242,7 @@ public boolean isFeasible() {
}
@Override
- public HardMediumSoftBigDecimalScore add(HardMediumSoftBigDecimalScore addend) {
+ public @NonNull HardMediumSoftBigDecimalScore add(@NonNull HardMediumSoftBigDecimalScore addend) {
return ofUninitialized(
initScore + addend.initScore(),
hardScore.add(addend.hardScore()),
@@ -244,7 +251,7 @@ public HardMediumSoftBigDecimalScore add(HardMediumSoftBigDecimalScore addend) {
}
@Override
- public HardMediumSoftBigDecimalScore subtract(HardMediumSoftBigDecimalScore subtrahend) {
+ public @NonNull HardMediumSoftBigDecimalScore subtract(@NonNull HardMediumSoftBigDecimalScore subtrahend) {
return ofUninitialized(
initScore - subtrahend.initScore(),
hardScore.subtract(subtrahend.hardScore()),
@@ -253,7 +260,7 @@ public HardMediumSoftBigDecimalScore subtract(HardMediumSoftBigDecimalScore subt
}
@Override
- public HardMediumSoftBigDecimalScore multiply(double multiplicand) {
+ public @NonNull HardMediumSoftBigDecimalScore multiply(double multiplicand) {
// Intentionally not taken "new BigDecimal(multiplicand, MathContext.UNLIMITED)"
// because together with the floor rounding it gives unwanted behaviour
BigDecimal multiplicandBigDecimal = BigDecimal.valueOf(multiplicand);
@@ -266,7 +273,7 @@ public HardMediumSoftBigDecimalScore multiply(double multiplicand) {
}
@Override
- public HardMediumSoftBigDecimalScore divide(double divisor) {
+ public @NonNull HardMediumSoftBigDecimalScore divide(double divisor) {
BigDecimal divisorBigDecimal = BigDecimal.valueOf(divisor);
// The (unspecified) scale/precision of the divisor should have no impact on the returned scale/precision
return ofUninitialized(
@@ -277,7 +284,7 @@ public HardMediumSoftBigDecimalScore divide(double divisor) {
}
@Override
- public HardMediumSoftBigDecimalScore power(double exponent) {
+ public @NonNull HardMediumSoftBigDecimalScore power(double exponent) {
BigDecimal exponentBigDecimal = BigDecimal.valueOf(exponent);
// The (unspecified) scale/precision of the exponent should have no impact on the returned scale/precision
// TODO FIXME remove .intValue() so non-integer exponents produce correct results
@@ -290,17 +297,17 @@ public HardMediumSoftBigDecimalScore power(double exponent) {
}
@Override
- public HardMediumSoftBigDecimalScore abs() {
+ public @NonNull HardMediumSoftBigDecimalScore abs() {
return ofUninitialized(Math.abs(initScore), hardScore.abs(), mediumScore.abs(), softScore.abs());
}
@Override
- public HardMediumSoftBigDecimalScore zero() {
+ public @NonNull HardMediumSoftBigDecimalScore zero() {
return HardMediumSoftBigDecimalScore.ZERO;
}
@Override
- public Number[] toLevelNumbers() {
+ public @NonNull Number @NonNull [] toLevelNumbers() {
return new Number[] { hardScore, mediumScore, softScore };
}
@@ -322,7 +329,7 @@ public int hashCode() {
}
@Override
- public int compareTo(HardMediumSoftBigDecimalScore other) {
+ public int compareTo(@NonNull HardMediumSoftBigDecimalScore other) {
if (initScore != other.initScore()) {
return Integer.compare(initScore, other.initScore());
}
@@ -339,7 +346,7 @@ public int compareTo(HardMediumSoftBigDecimalScore other) {
}
@Override
- public String toShortString() {
+ public @NonNull String toShortString() {
return ScoreUtil.buildShortString(this, n -> ((BigDecimal) n).compareTo(BigDecimal.ZERO) != 0,
HARD_LABEL, MEDIUM_LABEL, SOFT_LABEL);
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardmediumsoftlong/HardMediumSoftLongScore.java b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardmediumsoftlong/HardMediumSoftLongScore.java
index a99c483e8c..86740762fa 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardmediumsoftlong/HardMediumSoftLongScore.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardmediumsoftlong/HardMediumSoftLongScore.java
@@ -10,6 +10,8 @@
import ai.timefold.solver.core.api.score.Score;
import ai.timefold.solver.core.impl.score.ScoreUtil;
+import org.jspecify.annotations.NonNull;
+
/**
* This {@link Score} is based on 3 levels of long constraints: hard, medium and soft.
* Hard constraints have priority over medium constraints.
@@ -22,15 +24,15 @@
*/
public final class HardMediumSoftLongScore implements Score {
- public static final HardMediumSoftLongScore ZERO = new HardMediumSoftLongScore(0, 0L, 0L, 0L);
- public static final HardMediumSoftLongScore ONE_HARD = new HardMediumSoftLongScore(0, 1L, 0L, 0L);
- private static final HardMediumSoftLongScore MINUS_ONE_HARD = new HardMediumSoftLongScore(0, -1L, 0L, 0L);
- public static final HardMediumSoftLongScore ONE_MEDIUM = new HardMediumSoftLongScore(0, 0L, 1L, 0L);
- private static final HardMediumSoftLongScore MINUS_ONE_MEDIUM = new HardMediumSoftLongScore(0, 0L, -1L, 0L);
- public static final HardMediumSoftLongScore ONE_SOFT = new HardMediumSoftLongScore(0, 0L, 0L, 1L);
- private static final HardMediumSoftLongScore MINUS_ONE_SOFT = new HardMediumSoftLongScore(0, 0L, 0L, -1L);
+ public static final @NonNull HardMediumSoftLongScore ZERO = new HardMediumSoftLongScore(0, 0L, 0L, 0L);
+ public static final @NonNull HardMediumSoftLongScore ONE_HARD = new HardMediumSoftLongScore(0, 1L, 0L, 0L);
+ private static final @NonNull HardMediumSoftLongScore MINUS_ONE_HARD = new HardMediumSoftLongScore(0, -1L, 0L, 0L);
+ public static final @NonNull HardMediumSoftLongScore ONE_MEDIUM = new HardMediumSoftLongScore(0, 0L, 1L, 0L);
+ private static final @NonNull HardMediumSoftLongScore MINUS_ONE_MEDIUM = new HardMediumSoftLongScore(0, 0L, -1L, 0L);
+ public static final @NonNull HardMediumSoftLongScore ONE_SOFT = new HardMediumSoftLongScore(0, 0L, 0L, 1L);
+ private static final @NonNull HardMediumSoftLongScore MINUS_ONE_SOFT = new HardMediumSoftLongScore(0, 0L, 0L, -1L);
- public static HardMediumSoftLongScore parseScore(String scoreString) {
+ public static @NonNull HardMediumSoftLongScore parseScore(@NonNull String scoreString) {
String[] scoreTokens = ScoreUtil.parseScoreTokens(HardMediumSoftLongScore.class, scoreString,
HARD_LABEL, MEDIUM_LABEL, SOFT_LABEL);
int initScore = ScoreUtil.parseInitScore(HardMediumSoftLongScore.class, scoreString, scoreTokens[0]);
@@ -40,14 +42,15 @@ public static HardMediumSoftLongScore parseScore(String scoreString) {
return ofUninitialized(initScore, hardScore, mediumScore, softScore);
}
- public static HardMediumSoftLongScore ofUninitialized(int initScore, long hardScore, long mediumScore, long softScore) {
+ public static @NonNull HardMediumSoftLongScore ofUninitialized(int initScore, long hardScore, long mediumScore,
+ long softScore) {
if (initScore == 0) {
return of(hardScore, mediumScore, softScore);
}
return new HardMediumSoftLongScore(initScore, hardScore, mediumScore, softScore);
}
- public static HardMediumSoftLongScore of(long hardScore, long mediumScore, long softScore) {
+ public static @NonNull HardMediumSoftLongScore of(long hardScore, long mediumScore, long softScore) {
if (hardScore == -1L && mediumScore == 0L && softScore == 0L) {
return MINUS_ONE_HARD;
} else if (hardScore == 0L) {
@@ -70,7 +73,7 @@ public static HardMediumSoftLongScore of(long hardScore, long mediumScore, long
return new HardMediumSoftLongScore(0, hardScore, mediumScore, softScore);
}
- public static HardMediumSoftLongScore ofHard(long hardScore) {
+ public static @NonNull HardMediumSoftLongScore ofHard(long hardScore) {
if (hardScore == -1L) {
return MINUS_ONE_HARD;
} else if (hardScore == 0L) {
@@ -81,7 +84,7 @@ public static HardMediumSoftLongScore ofHard(long hardScore) {
return new HardMediumSoftLongScore(0, hardScore, 0L, 0L);
}
- public static HardMediumSoftLongScore ofMedium(long mediumScore) {
+ public static @NonNull HardMediumSoftLongScore ofMedium(long mediumScore) {
if (mediumScore == -1L) {
return MINUS_ONE_MEDIUM;
} else if (mediumScore == 0L) {
@@ -92,7 +95,7 @@ public static HardMediumSoftLongScore ofMedium(long mediumScore) {
return new HardMediumSoftLongScore(0, 0L, mediumScore, 0L);
}
- public static HardMediumSoftLongScore ofSoft(long softScore) {
+ public static @NonNull HardMediumSoftLongScore ofSoft(long softScore) {
if (softScore == -1L) {
return MINUS_ONE_SOFT;
} else if (softScore == 0L) {
@@ -206,7 +209,7 @@ public long getSoftScore() {
// ************************************************************************
@Override
- public HardMediumSoftLongScore withInitScore(int newInitScore) {
+ public @NonNull HardMediumSoftLongScore withInitScore(int newInitScore) {
return ofUninitialized(newInitScore, hardScore, mediumScore, softScore);
}
@@ -221,7 +224,7 @@ public boolean isFeasible() {
}
@Override
- public HardMediumSoftLongScore add(HardMediumSoftLongScore addend) {
+ public @NonNull HardMediumSoftLongScore add(@NonNull HardMediumSoftLongScore addend) {
return ofUninitialized(
initScore + addend.initScore(),
hardScore + addend.hardScore(),
@@ -230,7 +233,7 @@ public HardMediumSoftLongScore add(HardMediumSoftLongScore addend) {
}
@Override
- public HardMediumSoftLongScore subtract(HardMediumSoftLongScore subtrahend) {
+ public @NonNull HardMediumSoftLongScore subtract(@NonNull HardMediumSoftLongScore subtrahend) {
return ofUninitialized(
initScore - subtrahend.initScore(),
hardScore - subtrahend.hardScore(),
@@ -239,7 +242,7 @@ public HardMediumSoftLongScore subtract(HardMediumSoftLongScore subtrahend) {
}
@Override
- public HardMediumSoftLongScore multiply(double multiplicand) {
+ public @NonNull HardMediumSoftLongScore multiply(double multiplicand) {
return ofUninitialized(
(int) Math.floor(initScore * multiplicand),
(long) Math.floor(hardScore * multiplicand),
@@ -248,7 +251,7 @@ public HardMediumSoftLongScore multiply(double multiplicand) {
}
@Override
- public HardMediumSoftLongScore divide(double divisor) {
+ public @NonNull HardMediumSoftLongScore divide(double divisor) {
return ofUninitialized(
(int) Math.floor(initScore / divisor),
(long) Math.floor(hardScore / divisor),
@@ -257,7 +260,7 @@ public HardMediumSoftLongScore divide(double divisor) {
}
@Override
- public HardMediumSoftLongScore power(double exponent) {
+ public @NonNull HardMediumSoftLongScore power(double exponent) {
return ofUninitialized(
(int) Math.floor(Math.pow(initScore, exponent)),
(long) Math.floor(Math.pow(hardScore, exponent)),
@@ -266,17 +269,17 @@ public HardMediumSoftLongScore power(double exponent) {
}
@Override
- public HardMediumSoftLongScore abs() {
+ public @NonNull HardMediumSoftLongScore abs() {
return ofUninitialized(Math.abs(initScore), Math.abs(hardScore), Math.abs(mediumScore), Math.abs(softScore));
}
@Override
- public HardMediumSoftLongScore zero() {
+ public @NonNull HardMediumSoftLongScore zero() {
return HardMediumSoftLongScore.ZERO;
}
@Override
- public Number[] toLevelNumbers() {
+ public Number @NonNull [] toLevelNumbers() {
return new Number[] { hardScore, mediumScore, softScore };
}
@@ -297,7 +300,7 @@ public int hashCode() {
}
@Override
- public int compareTo(HardMediumSoftLongScore other) {
+ public int compareTo(@NonNull HardMediumSoftLongScore other) {
if (initScore != other.initScore()) {
return Integer.compare(initScore, other.initScore());
} else if (hardScore != other.hardScore()) {
@@ -310,7 +313,7 @@ public int compareTo(HardMediumSoftLongScore other) {
}
@Override
- public String toShortString() {
+ public @NonNull String toShortString() {
return ScoreUtil.buildShortString(this, n -> n.longValue() != 0L, HARD_LABEL, MEDIUM_LABEL, SOFT_LABEL);
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardsoft/HardSoftScore.java b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardsoft/HardSoftScore.java
index a3a6d24a70..572e94c796 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardsoft/HardSoftScore.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardsoft/HardSoftScore.java
@@ -11,6 +11,8 @@
import ai.timefold.solver.core.api.score.Score;
import ai.timefold.solver.core.impl.score.ScoreUtil;
+import org.jspecify.annotations.NonNull;
+
/**
* This {@link Score} is based on 2 levels of int constraints: hard and soft.
* Hard constraints have priority over soft constraints.
@@ -22,13 +24,13 @@
*/
public final class HardSoftScore implements Score {
- public static final HardSoftScore ZERO = new HardSoftScore(0, 0, 0);
- public static final HardSoftScore ONE_HARD = new HardSoftScore(0, 1, 0);
- public static final HardSoftScore ONE_SOFT = new HardSoftScore(0, 0, 1);
- private static final HardSoftScore MINUS_ONE_SOFT = new HardSoftScore(0, 0, -1);
- private static final HardSoftScore MINUS_ONE_HARD = new HardSoftScore(0, -1, 0);
+ public static final @NonNull HardSoftScore ZERO = new HardSoftScore(0, 0, 0);
+ public static final @NonNull HardSoftScore ONE_HARD = new HardSoftScore(0, 1, 0);
+ public static final @NonNull HardSoftScore ONE_SOFT = new HardSoftScore(0, 0, 1);
+ private static final @NonNull HardSoftScore MINUS_ONE_SOFT = new HardSoftScore(0, 0, -1);
+ private static final @NonNull HardSoftScore MINUS_ONE_HARD = new HardSoftScore(0, -1, 0);
- public static HardSoftScore parseScore(String scoreString) {
+ public static @NonNull HardSoftScore parseScore(@NonNull String scoreString) {
String[] scoreTokens = parseScoreTokens(HardSoftScore.class, scoreString, HARD_LABEL, SOFT_LABEL);
int initScore = parseInitScore(HardSoftScore.class, scoreString, scoreTokens[0]);
int hardScore = parseLevelAsInt(HardSoftScore.class, scoreString, scoreTokens[1]);
@@ -36,14 +38,14 @@ public static HardSoftScore parseScore(String scoreString) {
return ofUninitialized(initScore, hardScore, softScore);
}
- public static HardSoftScore ofUninitialized(int initScore, int hardScore, int softScore) {
+ public static @NonNull HardSoftScore ofUninitialized(int initScore, int hardScore, int softScore) {
if (initScore == 0) {
return of(hardScore, softScore);
}
return new HardSoftScore(initScore, hardScore, softScore);
}
- public static HardSoftScore of(int hardScore, int softScore) {
+ public static @NonNull HardSoftScore of(int hardScore, int softScore) {
// Optimization for frequently seen values.
if (hardScore == 0) {
if (softScore == -1) {
@@ -64,7 +66,7 @@ public static HardSoftScore of(int hardScore, int softScore) {
return new HardSoftScore(0, hardScore, softScore);
}
- public static HardSoftScore ofHard(int hardScore) {
+ public static @NonNull HardSoftScore ofHard(int hardScore) {
// Optimization for frequently seen values.
if (hardScore == -1) {
return MINUS_ONE_HARD;
@@ -77,7 +79,7 @@ public static HardSoftScore ofHard(int hardScore) {
return new HardSoftScore(0, hardScore, 0);
}
- public static HardSoftScore ofSoft(int softScore) {
+ public static @NonNull HardSoftScore ofSoft(int softScore) {
// Optimization for frequently seen values.
if (softScore == -1) {
return MINUS_ONE_SOFT;
@@ -168,7 +170,7 @@ public int getSoftScore() {
// ************************************************************************
@Override
- public HardSoftScore withInitScore(int newInitScore) {
+ public @NonNull HardSoftScore withInitScore(int newInitScore) {
return ofUninitialized(newInitScore, hardScore, softScore);
}
@@ -178,7 +180,7 @@ public boolean isFeasible() {
}
@Override
- public HardSoftScore add(HardSoftScore addend) {
+ public @NonNull HardSoftScore add(@NonNull HardSoftScore addend) {
return ofUninitialized(
initScore + addend.initScore(),
hardScore + addend.hardScore(),
@@ -186,7 +188,7 @@ public HardSoftScore add(HardSoftScore addend) {
}
@Override
- public HardSoftScore subtract(HardSoftScore subtrahend) {
+ public @NonNull HardSoftScore subtract(@NonNull HardSoftScore subtrahend) {
return ofUninitialized(
initScore - subtrahend.initScore(),
hardScore - subtrahend.hardScore(),
@@ -194,7 +196,7 @@ public HardSoftScore subtract(HardSoftScore subtrahend) {
}
@Override
- public HardSoftScore multiply(double multiplicand) {
+ public @NonNull HardSoftScore multiply(double multiplicand) {
return ofUninitialized(
(int) Math.floor(initScore * multiplicand),
(int) Math.floor(hardScore * multiplicand),
@@ -202,7 +204,7 @@ public HardSoftScore multiply(double multiplicand) {
}
@Override
- public HardSoftScore divide(double divisor) {
+ public @NonNull HardSoftScore divide(double divisor) {
return ofUninitialized(
(int) Math.floor(initScore / divisor),
(int) Math.floor(hardScore / divisor),
@@ -210,7 +212,7 @@ public HardSoftScore divide(double divisor) {
}
@Override
- public HardSoftScore power(double exponent) {
+ public @NonNull HardSoftScore power(double exponent) {
return ofUninitialized(
(int) Math.floor(Math.pow(initScore, exponent)),
(int) Math.floor(Math.pow(hardScore, exponent)),
@@ -218,17 +220,17 @@ public HardSoftScore power(double exponent) {
}
@Override
- public HardSoftScore abs() {
+ public @NonNull HardSoftScore abs() {
return ofUninitialized(Math.abs(initScore), Math.abs(hardScore), Math.abs(softScore));
}
@Override
- public HardSoftScore zero() {
+ public @NonNull HardSoftScore zero() {
return ZERO;
}
@Override
- public Number[] toLevelNumbers() {
+ public Number @NonNull [] toLevelNumbers() {
return new Number[] { hardScore, softScore };
}
@@ -248,7 +250,7 @@ public int hashCode() {
}
@Override
- public int compareTo(HardSoftScore other) {
+ public int compareTo(@NonNull HardSoftScore other) {
if (initScore != other.initScore()) {
return Integer.compare(initScore, other.initScore());
} else if (hardScore != other.hardScore()) {
@@ -259,7 +261,7 @@ public int compareTo(HardSoftScore other) {
}
@Override
- public String toShortString() {
+ public @NonNull String toShortString() {
return ScoreUtil.buildShortString(this, n -> n.intValue() != 0, HARD_LABEL, SOFT_LABEL);
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardsoftbigdecimal/HardSoftBigDecimalScore.java b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardsoftbigdecimal/HardSoftBigDecimalScore.java
index 5b7583e564..d6ab3850db 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardsoftbigdecimal/HardSoftBigDecimalScore.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardsoftbigdecimal/HardSoftBigDecimalScore.java
@@ -10,6 +10,8 @@
import ai.timefold.solver.core.api.score.Score;
import ai.timefold.solver.core.impl.score.ScoreUtil;
+import org.jspecify.annotations.NonNull;
+
/**
* This {@link Score} is based on 2 levels of {@link BigDecimal} constraints: hard and soft.
* Hard constraints have priority over soft constraints.
@@ -21,11 +23,14 @@
*/
public final class HardSoftBigDecimalScore implements Score {
- public static final HardSoftBigDecimalScore ZERO = new HardSoftBigDecimalScore(0, BigDecimal.ZERO, BigDecimal.ZERO);
- public static final HardSoftBigDecimalScore ONE_HARD = new HardSoftBigDecimalScore(0, BigDecimal.ONE, BigDecimal.ZERO);
- public static final HardSoftBigDecimalScore ONE_SOFT = new HardSoftBigDecimalScore(0, BigDecimal.ZERO, BigDecimal.ONE);
+ public static final @NonNull HardSoftBigDecimalScore ZERO =
+ new HardSoftBigDecimalScore(0, BigDecimal.ZERO, BigDecimal.ZERO);
+ public static final @NonNull HardSoftBigDecimalScore ONE_HARD =
+ new HardSoftBigDecimalScore(0, BigDecimal.ONE, BigDecimal.ZERO);
+ public static final @NonNull HardSoftBigDecimalScore ONE_SOFT =
+ new HardSoftBigDecimalScore(0, BigDecimal.ZERO, BigDecimal.ONE);
- public static HardSoftBigDecimalScore parseScore(String scoreString) {
+ public static @NonNull HardSoftBigDecimalScore parseScore(@NonNull String scoreString) {
String[] scoreTokens = ScoreUtil.parseScoreTokens(HardSoftBigDecimalScore.class, scoreString, HARD_LABEL, SOFT_LABEL);
int initScore = ScoreUtil.parseInitScore(HardSoftBigDecimalScore.class, scoreString, scoreTokens[0]);
BigDecimal hardScore = ScoreUtil.parseLevelAsBigDecimal(HardSoftBigDecimalScore.class, scoreString, scoreTokens[1]);
@@ -33,14 +38,15 @@ public static HardSoftBigDecimalScore parseScore(String scoreString) {
return ofUninitialized(initScore, hardScore, softScore);
}
- public static HardSoftBigDecimalScore ofUninitialized(int initScore, BigDecimal hardScore, BigDecimal softScore) {
+ public static @NonNull HardSoftBigDecimalScore ofUninitialized(int initScore, @NonNull BigDecimal hardScore,
+ @NonNull BigDecimal softScore) {
if (initScore == 0) {
return of(hardScore, softScore);
}
return new HardSoftBigDecimalScore(initScore, hardScore, softScore);
}
- public static HardSoftBigDecimalScore of(BigDecimal hardScore, BigDecimal softScore) {
+ public static @NonNull HardSoftBigDecimalScore of(BigDecimal hardScore, BigDecimal softScore) {
// Optimization for frequently seen values.
if (hardScore.signum() == 0) {
if (softScore.signum() == 0) {
@@ -55,7 +61,7 @@ public static HardSoftBigDecimalScore of(BigDecimal hardScore, BigDecimal softSc
return new HardSoftBigDecimalScore(0, hardScore, softScore);
}
- public static HardSoftBigDecimalScore ofHard(BigDecimal hardScore) {
+ public static @NonNull HardSoftBigDecimalScore ofHard(BigDecimal hardScore) {
// Optimization for frequently seen values.
if (hardScore.signum() == 0) {
return ZERO;
@@ -66,7 +72,7 @@ public static HardSoftBigDecimalScore ofHard(BigDecimal hardScore) {
return new HardSoftBigDecimalScore(0, hardScore, BigDecimal.ZERO);
}
- public static HardSoftBigDecimalScore ofSoft(BigDecimal softScore) {
+ public static @NonNull HardSoftBigDecimalScore ofSoft(BigDecimal softScore) {
// Optimization for frequently seen values.
if (softScore.signum() == 0) {
return ZERO;
@@ -82,8 +88,8 @@ public static HardSoftBigDecimalScore ofSoft(BigDecimal softScore) {
// ************************************************************************
private final int initScore;
- private final BigDecimal hardScore;
- private final BigDecimal softScore;
+ private final @NonNull BigDecimal hardScore;
+ private final @NonNull BigDecimal softScore;
/**
* Private default constructor for default marshalling/unmarshalling of unknown frameworks that use reflection.
@@ -92,10 +98,10 @@ public static HardSoftBigDecimalScore ofSoft(BigDecimal softScore) {
*/
@SuppressWarnings("unused")
private HardSoftBigDecimalScore() {
- this(Integer.MIN_VALUE, null, null);
+ this(Integer.MIN_VALUE, BigDecimal.ZERO, BigDecimal.ZERO);
}
- private HardSoftBigDecimalScore(int initScore, BigDecimal hardScore, BigDecimal softScore) {
+ private HardSoftBigDecimalScore(int initScore, @NonNull BigDecimal hardScore, @NonNull BigDecimal softScore) {
this.initScore = initScore;
this.hardScore = hardScore;
this.softScore = softScore;
@@ -113,7 +119,7 @@ public int initScore() {
*
* @return higher is better, usually negative, 0 if no hard constraints are broken/fulfilled
*/
- public BigDecimal hardScore() {
+ public @NonNull BigDecimal hardScore() {
return hardScore;
}
@@ -123,7 +129,7 @@ public BigDecimal hardScore() {
* @deprecated Use {@link #hardScore()} instead.
*/
@Deprecated(forRemoval = true)
- public BigDecimal getHardScore() {
+ public @NonNull BigDecimal getHardScore() {
return hardScore;
}
@@ -136,7 +142,7 @@ public BigDecimal getHardScore() {
*
* @return higher is better, usually negative, 0 if no soft constraints are broken/fulfilled
*/
- public BigDecimal softScore() {
+ public @NonNull BigDecimal softScore() {
return softScore;
}
@@ -146,7 +152,7 @@ public BigDecimal softScore() {
* @deprecated Use {@link #softScore()} instead.
*/
@Deprecated(forRemoval = true)
- public BigDecimal getSoftScore() {
+ public @NonNull BigDecimal getSoftScore() {
return softScore;
}
@@ -155,7 +161,7 @@ public BigDecimal getSoftScore() {
// ************************************************************************
@Override
- public HardSoftBigDecimalScore withInitScore(int newInitScore) {
+ public @NonNull HardSoftBigDecimalScore withInitScore(int newInitScore) {
return new HardSoftBigDecimalScore(newInitScore, hardScore, softScore);
}
@@ -165,7 +171,7 @@ public boolean isFeasible() {
}
@Override
- public HardSoftBigDecimalScore add(HardSoftBigDecimalScore addend) {
+ public @NonNull HardSoftBigDecimalScore add(@NonNull HardSoftBigDecimalScore addend) {
return ofUninitialized(
initScore + addend.initScore(),
hardScore.add(addend.hardScore()),
@@ -173,7 +179,7 @@ public HardSoftBigDecimalScore add(HardSoftBigDecimalScore addend) {
}
@Override
- public HardSoftBigDecimalScore subtract(HardSoftBigDecimalScore subtrahend) {
+ public @NonNull HardSoftBigDecimalScore subtract(@NonNull HardSoftBigDecimalScore subtrahend) {
return ofUninitialized(
initScore - subtrahend.initScore(),
hardScore.subtract(subtrahend.hardScore()),
@@ -181,7 +187,7 @@ public HardSoftBigDecimalScore subtract(HardSoftBigDecimalScore subtrahend) {
}
@Override
- public HardSoftBigDecimalScore multiply(double multiplicand) {
+ public @NonNull HardSoftBigDecimalScore multiply(double multiplicand) {
// Intentionally not taken "new BigDecimal(multiplicand, MathContext.UNLIMITED)"
// because together with the floor rounding it gives unwanted behaviour
BigDecimal multiplicandBigDecimal = BigDecimal.valueOf(multiplicand);
@@ -193,7 +199,7 @@ public HardSoftBigDecimalScore multiply(double multiplicand) {
}
@Override
- public HardSoftBigDecimalScore divide(double divisor) {
+ public @NonNull HardSoftBigDecimalScore divide(double divisor) {
// Intentionally not taken "new BigDecimal(multiplicand, MathContext.UNLIMITED)"
// because together with the floor rounding it gives unwanted behaviour
BigDecimal divisorBigDecimal = BigDecimal.valueOf(divisor);
@@ -205,7 +211,7 @@ public HardSoftBigDecimalScore divide(double divisor) {
}
@Override
- public HardSoftBigDecimalScore power(double exponent) {
+ public @NonNull HardSoftBigDecimalScore power(double exponent) {
// Intentionally not taken "new BigDecimal(multiplicand, MathContext.UNLIMITED)"
// because together with the floor rounding it gives unwanted behaviour
BigDecimal exponentBigDecimal = BigDecimal.valueOf(exponent);
@@ -219,17 +225,17 @@ public HardSoftBigDecimalScore power(double exponent) {
}
@Override
- public HardSoftBigDecimalScore abs() {
+ public @NonNull HardSoftBigDecimalScore abs() {
return ofUninitialized(Math.abs(initScore), hardScore.abs(), softScore.abs());
}
@Override
- public HardSoftBigDecimalScore zero() {
+ public @NonNull HardSoftBigDecimalScore zero() {
return ZERO;
}
@Override
- public Number[] toLevelNumbers() {
+ public Number @NonNull [] toLevelNumbers() {
return new Number[] { hardScore, softScore };
}
@@ -249,7 +255,7 @@ public int hashCode() {
}
@Override
- public int compareTo(HardSoftBigDecimalScore other) {
+ public int compareTo(@NonNull HardSoftBigDecimalScore other) {
if (initScore != other.initScore()) {
return Integer.compare(initScore, other.initScore());
}
@@ -262,7 +268,7 @@ public int compareTo(HardSoftBigDecimalScore other) {
}
@Override
- public String toShortString() {
+ public @NonNull String toShortString() {
return ScoreUtil.buildShortString(this, n -> ((BigDecimal) n).compareTo(BigDecimal.ZERO) != 0, HARD_LABEL, SOFT_LABEL);
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardsoftlong/HardSoftLongScore.java b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardsoftlong/HardSoftLongScore.java
index 03cb975130..1826ab5050 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardsoftlong/HardSoftLongScore.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/hardsoftlong/HardSoftLongScore.java
@@ -8,6 +8,8 @@
import ai.timefold.solver.core.api.score.Score;
import ai.timefold.solver.core.impl.score.ScoreUtil;
+import org.jspecify.annotations.NonNull;
+
/**
* This {@link Score} is based on 2 levels of long constraints: hard and soft.
* Hard constraints have priority over soft constraints.
@@ -19,13 +21,13 @@
*/
public final class HardSoftLongScore implements Score {
- public static final HardSoftLongScore ZERO = new HardSoftLongScore(0, 0L, 0L);
- public static final HardSoftLongScore ONE_HARD = new HardSoftLongScore(0, 1L, 0L);
- public static final HardSoftLongScore ONE_SOFT = new HardSoftLongScore(0, 0L, 1L);
- private static final HardSoftLongScore MINUS_ONE_SOFT = new HardSoftLongScore(0, 0L, -1L);
- private static final HardSoftLongScore MINUS_ONE_HARD = new HardSoftLongScore(0, -1L, 0L);
+ public static final @NonNull HardSoftLongScore ZERO = new HardSoftLongScore(0, 0L, 0L);
+ public static final @NonNull HardSoftLongScore ONE_HARD = new HardSoftLongScore(0, 1L, 0L);
+ public static final @NonNull HardSoftLongScore ONE_SOFT = new HardSoftLongScore(0, 0L, 1L);
+ private static final @NonNull HardSoftLongScore MINUS_ONE_SOFT = new HardSoftLongScore(0, 0L, -1L);
+ private static final @NonNull HardSoftLongScore MINUS_ONE_HARD = new HardSoftLongScore(0, -1L, 0L);
- public static HardSoftLongScore parseScore(String scoreString) {
+ public static @NonNull HardSoftLongScore parseScore(@NonNull String scoreString) {
String[] scoreTokens = ScoreUtil.parseScoreTokens(HardSoftLongScore.class, scoreString, HARD_LABEL, SOFT_LABEL);
int initScore = ScoreUtil.parseInitScore(HardSoftLongScore.class, scoreString, scoreTokens[0]);
long hardScore = ScoreUtil.parseLevelAsLong(HardSoftLongScore.class, scoreString, scoreTokens[1]);
@@ -33,14 +35,14 @@ public static HardSoftLongScore parseScore(String scoreString) {
return ofUninitialized(initScore, hardScore, softScore);
}
- public static HardSoftLongScore ofUninitialized(int initScore, long hardScore, long softScore) {
+ public static @NonNull HardSoftLongScore ofUninitialized(int initScore, long hardScore, long softScore) {
if (initScore == 0) {
return of(hardScore, softScore);
}
return new HardSoftLongScore(initScore, hardScore, softScore);
}
- public static HardSoftLongScore of(long hardScore, long softScore) {
+ public static @NonNull HardSoftLongScore of(long hardScore, long softScore) {
// Optimization for frequently seen values.
if (hardScore == 0L) {
if (softScore == -1L) {
@@ -61,7 +63,7 @@ public static HardSoftLongScore of(long hardScore, long softScore) {
return new HardSoftLongScore(0, hardScore, softScore);
}
- public static HardSoftLongScore ofHard(long hardScore) {
+ public static @NonNull HardSoftLongScore ofHard(long hardScore) {
// Optimization for frequently seen values.
if (hardScore == -1L) {
return MINUS_ONE_HARD;
@@ -74,7 +76,7 @@ public static HardSoftLongScore ofHard(long hardScore) {
return new HardSoftLongScore(0, hardScore, 0L);
}
- public static HardSoftLongScore ofSoft(long softScore) {
+ public static @NonNull HardSoftLongScore ofSoft(long softScore) {
// Optimization for frequently seen values.
if (softScore == -1L) {
return MINUS_ONE_SOFT;
@@ -165,7 +167,7 @@ public long getSoftScore() {
// ************************************************************************
@Override
- public HardSoftLongScore withInitScore(int newInitScore) {
+ public @NonNull HardSoftLongScore withInitScore(int newInitScore) {
return ofUninitialized(newInitScore, hardScore, softScore);
}
@@ -175,7 +177,7 @@ public boolean isFeasible() {
}
@Override
- public HardSoftLongScore add(HardSoftLongScore addend) {
+ public @NonNull HardSoftLongScore add(@NonNull HardSoftLongScore addend) {
return ofUninitialized(
initScore + addend.initScore(),
hardScore + addend.hardScore(),
@@ -183,7 +185,7 @@ public HardSoftLongScore add(HardSoftLongScore addend) {
}
@Override
- public HardSoftLongScore subtract(HardSoftLongScore subtrahend) {
+ public @NonNull HardSoftLongScore subtract(@NonNull HardSoftLongScore subtrahend) {
return ofUninitialized(
initScore - subtrahend.initScore(),
hardScore - subtrahend.hardScore(),
@@ -191,7 +193,7 @@ public HardSoftLongScore subtract(HardSoftLongScore subtrahend) {
}
@Override
- public HardSoftLongScore multiply(double multiplicand) {
+ public @NonNull HardSoftLongScore multiply(double multiplicand) {
return ofUninitialized(
(int) Math.floor(initScore * multiplicand),
(long) Math.floor(hardScore * multiplicand),
@@ -199,7 +201,7 @@ public HardSoftLongScore multiply(double multiplicand) {
}
@Override
- public HardSoftLongScore divide(double divisor) {
+ public @NonNull HardSoftLongScore divide(double divisor) {
return ofUninitialized(
(int) Math.floor(initScore / divisor),
(long) Math.floor(hardScore / divisor),
@@ -207,7 +209,7 @@ public HardSoftLongScore divide(double divisor) {
}
@Override
- public HardSoftLongScore power(double exponent) {
+ public @NonNull HardSoftLongScore power(double exponent) {
return ofUninitialized(
(int) Math.floor(Math.pow(initScore, exponent)),
(long) Math.floor(Math.pow(hardScore, exponent)),
@@ -215,17 +217,17 @@ public HardSoftLongScore power(double exponent) {
}
@Override
- public HardSoftLongScore abs() {
+ public @NonNull HardSoftLongScore abs() {
return ofUninitialized(Math.abs(initScore), Math.abs(hardScore), Math.abs(softScore));
}
@Override
- public HardSoftLongScore zero() {
+ public @NonNull HardSoftLongScore zero() {
return ZERO;
}
@Override
- public Number[] toLevelNumbers() {
+ public Number @NonNull [] toLevelNumbers() {
return new Number[] { hardScore, softScore };
}
@@ -245,7 +247,7 @@ public int hashCode() {
}
@Override
- public int compareTo(HardSoftLongScore other) {
+ public int compareTo(@NonNull HardSoftLongScore other) {
if (initScore != other.initScore()) {
return Integer.compare(initScore, other.initScore());
} else if (hardScore != other.hardScore()) {
@@ -256,7 +258,7 @@ public int compareTo(HardSoftLongScore other) {
}
@Override
- public String toShortString() {
+ public @NonNull String toShortString() {
return ScoreUtil.buildShortString(this, n -> n.longValue() != 0L, HARD_LABEL, SOFT_LABEL);
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/simple/SimpleScore.java b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/simple/SimpleScore.java
index 66ab62d3aa..d2d8ed7fd6 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/simple/SimpleScore.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/simple/SimpleScore.java
@@ -5,6 +5,8 @@
import ai.timefold.solver.core.api.score.Score;
import ai.timefold.solver.core.impl.score.ScoreUtil;
+import org.jspecify.annotations.NonNull;
+
/**
* This {@link Score} is based on 1 level of int constraints.
*
@@ -18,21 +20,21 @@ public final class SimpleScore implements Score {
public static final SimpleScore ONE = new SimpleScore(0, 1);
private static final SimpleScore MINUS_ONE = new SimpleScore(0, -1);
- public static SimpleScore parseScore(String scoreString) {
+ public static @NonNull SimpleScore parseScore(@NonNull String scoreString) {
String[] scoreTokens = ScoreUtil.parseScoreTokens(SimpleScore.class, scoreString, "");
int initScore = ScoreUtil.parseInitScore(SimpleScore.class, scoreString, scoreTokens[0]);
int score = ScoreUtil.parseLevelAsInt(SimpleScore.class, scoreString, scoreTokens[1]);
return ofUninitialized(initScore, score);
}
- public static SimpleScore ofUninitialized(int initScore, int score) {
+ public static @NonNull SimpleScore ofUninitialized(int initScore, int score) {
if (initScore == 0) {
return of(score);
}
return new SimpleScore(initScore, score);
}
- public static SimpleScore of(int score) {
+ public static @NonNull SimpleScore of(int score) {
return switch (score) {
case -1 -> MINUS_ONE;
case 0 -> ZERO;
@@ -94,52 +96,52 @@ public int getScore() {
// ************************************************************************
@Override
- public SimpleScore withInitScore(int newInitScore) {
+ public @NonNull SimpleScore withInitScore(int newInitScore) {
return ofUninitialized(newInitScore, score);
}
@Override
- public SimpleScore add(SimpleScore addend) {
+ public @NonNull SimpleScore add(@NonNull SimpleScore addend) {
return ofUninitialized(
initScore + addend.initScore(),
score + addend.score());
}
@Override
- public SimpleScore subtract(SimpleScore subtrahend) {
+ public @NonNull SimpleScore subtract(@NonNull SimpleScore subtrahend) {
return ofUninitialized(
initScore - subtrahend.initScore(),
score - subtrahend.score());
}
@Override
- public SimpleScore multiply(double multiplicand) {
+ public @NonNull SimpleScore multiply(double multiplicand) {
return ofUninitialized(
(int) Math.floor(initScore * multiplicand),
(int) Math.floor(score * multiplicand));
}
@Override
- public SimpleScore divide(double divisor) {
+ public @NonNull SimpleScore divide(double divisor) {
return ofUninitialized(
(int) Math.floor(initScore / divisor),
(int) Math.floor(score / divisor));
}
@Override
- public SimpleScore power(double exponent) {
+ public @NonNull SimpleScore power(double exponent) {
return ofUninitialized(
(int) Math.floor(Math.pow(initScore, exponent)),
(int) Math.floor(Math.pow(score, exponent)));
}
@Override
- public SimpleScore abs() {
+ public @NonNull SimpleScore abs() {
return ofUninitialized(Math.abs(initScore), Math.abs(score));
}
@Override
- public SimpleScore zero() {
+ public @NonNull SimpleScore zero() {
return ZERO;
}
@@ -149,7 +151,7 @@ public boolean isFeasible() {
}
@Override
- public Number[] toLevelNumbers() {
+ public Number @NonNull [] toLevelNumbers() {
return new Number[] { score };
}
@@ -168,7 +170,7 @@ public int hashCode() {
}
@Override
- public int compareTo(SimpleScore other) {
+ public int compareTo(@NonNull SimpleScore other) {
if (initScore != other.initScore()) {
return Integer.compare(initScore, other.initScore());
} else {
@@ -177,7 +179,7 @@ public int compareTo(SimpleScore other) {
}
@Override
- public String toShortString() {
+ public @NonNull String toShortString() {
return ScoreUtil.buildShortString(this, n -> n.intValue() != 0, "");
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/simplebigdecimal/SimpleBigDecimalScore.java b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/simplebigdecimal/SimpleBigDecimalScore.java
index a761370f4d..ab11406cd1 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/simplebigdecimal/SimpleBigDecimalScore.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/simplebigdecimal/SimpleBigDecimalScore.java
@@ -7,6 +7,8 @@
import ai.timefold.solver.core.api.score.Score;
import ai.timefold.solver.core.impl.score.ScoreUtil;
+import org.jspecify.annotations.NonNull;
+
/**
* This {@link Score} is based on 1 level of {@link BigDecimal} constraints.
*
@@ -16,24 +18,24 @@
*/
public final class SimpleBigDecimalScore implements Score {
- public static final SimpleBigDecimalScore ZERO = new SimpleBigDecimalScore(0, BigDecimal.ZERO);
- public static final SimpleBigDecimalScore ONE = new SimpleBigDecimalScore(0, BigDecimal.ONE);
+ public static final @NonNull SimpleBigDecimalScore ZERO = new SimpleBigDecimalScore(0, BigDecimal.ZERO);
+ public static final @NonNull SimpleBigDecimalScore ONE = new SimpleBigDecimalScore(0, BigDecimal.ONE);
- public static SimpleBigDecimalScore parseScore(String scoreString) {
+ public static @NonNull SimpleBigDecimalScore parseScore(@NonNull String scoreString) {
String[] scoreTokens = ScoreUtil.parseScoreTokens(SimpleBigDecimalScore.class, scoreString, "");
int initScore = ScoreUtil.parseInitScore(SimpleBigDecimalScore.class, scoreString, scoreTokens[0]);
BigDecimal score = ScoreUtil.parseLevelAsBigDecimal(SimpleBigDecimalScore.class, scoreString, scoreTokens[1]);
return ofUninitialized(initScore, score);
}
- public static SimpleBigDecimalScore ofUninitialized(int initScore, BigDecimal score) {
+ public static @NonNull SimpleBigDecimalScore ofUninitialized(int initScore, @NonNull BigDecimal score) {
if (initScore == 0) {
return of(score);
}
return new SimpleBigDecimalScore(initScore, score);
}
- public static SimpleBigDecimalScore of(BigDecimal score) {
+ public static @NonNull SimpleBigDecimalScore of(@NonNull BigDecimal score) {
if (score.signum() == 0) {
return ZERO;
} else if (score.equals(BigDecimal.ONE)) {
@@ -48,7 +50,7 @@ public static SimpleBigDecimalScore of(BigDecimal score) {
// ************************************************************************
private final int initScore;
- private final BigDecimal score;
+ private final @NonNull BigDecimal score;
/**
* Private default constructor for default marshalling/unmarshalling of unknown frameworks that use reflection.
@@ -57,10 +59,10 @@ public static SimpleBigDecimalScore of(BigDecimal score) {
*/
@SuppressWarnings("unused")
private SimpleBigDecimalScore() {
- this(Integer.MIN_VALUE, null);
+ this(Integer.MIN_VALUE, BigDecimal.ZERO);
}
- private SimpleBigDecimalScore(int initScore, BigDecimal score) {
+ private SimpleBigDecimalScore(int initScore, @NonNull BigDecimal score) {
this.initScore = initScore;
this.score = score;
}
@@ -77,7 +79,7 @@ public int initScore() {
*
* @return higher is better, usually negative, 0 if no constraints are broken/fulfilled
*/
- public BigDecimal score() {
+ public @NonNull BigDecimal score() {
return score;
}
@@ -87,7 +89,7 @@ public BigDecimal score() {
* @deprecated Use {@link #score()} instead.
*/
@Deprecated(forRemoval = true)
- public BigDecimal getScore() {
+ public @NonNull BigDecimal getScore() {
return score;
}
@@ -96,26 +98,26 @@ public BigDecimal getScore() {
// ************************************************************************
@Override
- public SimpleBigDecimalScore withInitScore(int newInitScore) {
+ public @NonNull SimpleBigDecimalScore withInitScore(int newInitScore) {
return ofUninitialized(newInitScore, score);
}
@Override
- public SimpleBigDecimalScore add(SimpleBigDecimalScore addend) {
+ public @NonNull SimpleBigDecimalScore add(@NonNull SimpleBigDecimalScore addend) {
return ofUninitialized(
initScore + addend.initScore(),
score.add(addend.score()));
}
@Override
- public SimpleBigDecimalScore subtract(SimpleBigDecimalScore subtrahend) {
+ public @NonNull SimpleBigDecimalScore subtract(@NonNull SimpleBigDecimalScore subtrahend) {
return ofUninitialized(
initScore - subtrahend.initScore(),
score.subtract(subtrahend.score()));
}
@Override
- public SimpleBigDecimalScore multiply(double multiplicand) {
+ public @NonNull SimpleBigDecimalScore multiply(double multiplicand) {
// Intentionally not taken "new BigDecimal(multiplicand, MathContext.UNLIMITED)"
// because together with the floor rounding it gives unwanted behaviour
BigDecimal multiplicandBigDecimal = BigDecimal.valueOf(multiplicand);
@@ -126,7 +128,7 @@ public SimpleBigDecimalScore multiply(double multiplicand) {
}
@Override
- public SimpleBigDecimalScore divide(double divisor) {
+ public @NonNull SimpleBigDecimalScore divide(double divisor) {
// Intentionally not taken "new BigDecimal(multiplicand, MathContext.UNLIMITED)"
// because together with the floor rounding it gives unwanted behaviour
BigDecimal divisorBigDecimal = BigDecimal.valueOf(divisor);
@@ -137,7 +139,7 @@ public SimpleBigDecimalScore divide(double divisor) {
}
@Override
- public SimpleBigDecimalScore power(double exponent) {
+ public @NonNull SimpleBigDecimalScore power(double exponent) {
// Intentionally not taken "new BigDecimal(multiplicand, MathContext.UNLIMITED)"
// because together with the floor rounding it gives unwanted behaviour
BigDecimal exponentBigDecimal = BigDecimal.valueOf(exponent);
@@ -150,12 +152,12 @@ public SimpleBigDecimalScore power(double exponent) {
}
@Override
- public SimpleBigDecimalScore abs() {
+ public @NonNull SimpleBigDecimalScore abs() {
return ofUninitialized(Math.abs(initScore), score.abs());
}
@Override
- public SimpleBigDecimalScore zero() {
+ public @NonNull SimpleBigDecimalScore zero() {
return ZERO;
}
@@ -165,7 +167,7 @@ public boolean isFeasible() {
}
@Override
- public Number[] toLevelNumbers() {
+ public @NonNull Number @NonNull [] toLevelNumbers() {
return new Number[] { score };
}
@@ -184,7 +186,7 @@ public int hashCode() {
}
@Override
- public int compareTo(SimpleBigDecimalScore other) {
+ public int compareTo(@NonNull SimpleBigDecimalScore other) {
if (initScore != other.initScore()) {
return Integer.compare(initScore, other.initScore());
} else {
@@ -193,7 +195,7 @@ public int compareTo(SimpleBigDecimalScore other) {
}
@Override
- public String toShortString() {
+ public @NonNull String toShortString() {
return ScoreUtil.buildShortString(this, n -> ((BigDecimal) n).compareTo(BigDecimal.ZERO) != 0, "");
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/simplelong/SimpleLongScore.java b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/simplelong/SimpleLongScore.java
index 882f9d2afb..34a0cb7215 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/buildin/simplelong/SimpleLongScore.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/buildin/simplelong/SimpleLongScore.java
@@ -5,6 +5,8 @@
import ai.timefold.solver.core.api.score.Score;
import ai.timefold.solver.core.impl.score.ScoreUtil;
+import org.jspecify.annotations.NonNull;
+
/**
* This {@link Score} is based on 1 level of long constraints.
*
@@ -18,21 +20,21 @@ public final class SimpleLongScore implements Score {
public static final SimpleLongScore ONE = new SimpleLongScore(0, 1L);
public static final SimpleLongScore MINUS_ONE = new SimpleLongScore(0, -1L);
- public static SimpleLongScore parseScore(String scoreString) {
+ public static @NonNull SimpleLongScore parseScore(@NonNull String scoreString) {
String[] scoreTokens = ScoreUtil.parseScoreTokens(SimpleLongScore.class, scoreString, "");
int initScore = ScoreUtil.parseInitScore(SimpleLongScore.class, scoreString, scoreTokens[0]);
long score = ScoreUtil.parseLevelAsLong(SimpleLongScore.class, scoreString, scoreTokens[1]);
return ofUninitialized(initScore, score);
}
- public static SimpleLongScore ofUninitialized(int initScore, long score) {
+ public static @NonNull SimpleLongScore ofUninitialized(int initScore, long score) {
if (initScore == 0) {
return of(score);
}
return new SimpleLongScore(initScore, score);
}
- public static SimpleLongScore of(long score) {
+ public static @NonNull SimpleLongScore of(long score) {
if (score == -1L) {
return MINUS_ONE;
} else if (score == 0L) {
@@ -97,52 +99,52 @@ public long getScore() {
// ************************************************************************
@Override
- public SimpleLongScore withInitScore(int newInitScore) {
+ public @NonNull SimpleLongScore withInitScore(int newInitScore) {
return ofUninitialized(newInitScore, score);
}
@Override
- public SimpleLongScore add(SimpleLongScore addend) {
+ public @NonNull SimpleLongScore add(@NonNull SimpleLongScore addend) {
return ofUninitialized(
initScore + addend.initScore(),
score + addend.score());
}
@Override
- public SimpleLongScore subtract(SimpleLongScore subtrahend) {
+ public @NonNull SimpleLongScore subtract(@NonNull SimpleLongScore subtrahend) {
return ofUninitialized(
initScore - subtrahend.initScore(),
score - subtrahend.score());
}
@Override
- public SimpleLongScore multiply(double multiplicand) {
+ public @NonNull SimpleLongScore multiply(double multiplicand) {
return ofUninitialized(
(int) Math.floor(initScore * multiplicand),
(long) Math.floor(score * multiplicand));
}
@Override
- public SimpleLongScore divide(double divisor) {
+ public @NonNull SimpleLongScore divide(double divisor) {
return ofUninitialized(
(int) Math.floor(initScore / divisor),
(long) Math.floor(score / divisor));
}
@Override
- public SimpleLongScore power(double exponent) {
+ public @NonNull SimpleLongScore power(double exponent) {
return ofUninitialized(
(int) Math.floor(Math.pow(initScore, exponent)),
(long) Math.floor(Math.pow(score, exponent)));
}
@Override
- public SimpleLongScore abs() {
+ public @NonNull SimpleLongScore abs() {
return ofUninitialized(Math.abs(initScore), Math.abs(score));
}
@Override
- public SimpleLongScore zero() {
+ public @NonNull SimpleLongScore zero() {
return ZERO;
}
@@ -152,7 +154,7 @@ public boolean isFeasible() {
}
@Override
- public Number[] toLevelNumbers() {
+ public Number @NonNull [] toLevelNumbers() {
return new Number[] { score };
}
@@ -171,7 +173,7 @@ public int hashCode() {
}
@Override
- public int compareTo(SimpleLongScore other) {
+ public int compareTo(@NonNull SimpleLongScore other) {
if (initScore != other.initScore()) {
return Integer.compare(initScore, other.initScore());
} else {
@@ -180,7 +182,7 @@ public int compareTo(SimpleLongScore other) {
}
@Override
- public String toShortString() {
+ public @NonNull String toShortString() {
return ScoreUtil.buildShortString(this, n -> n.longValue() != 0L, "");
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/calculator/ConstraintMatchAwareIncrementalScoreCalculator.java b/core/src/main/java/ai/timefold/solver/core/api/score/calculator/ConstraintMatchAwareIncrementalScoreCalculator.java
index ea5ae5afda..396b0232f0 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/calculator/ConstraintMatchAwareIncrementalScoreCalculator.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/calculator/ConstraintMatchAwareIncrementalScoreCalculator.java
@@ -9,6 +9,9 @@
import ai.timefold.solver.core.api.score.constraint.ConstraintMatchTotal;
import ai.timefold.solver.core.api.score.constraint.Indictment;
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
/**
* Allows a {@link IncrementalScoreCalculator} to report {@link ConstraintMatchTotal}s
* for explaining a score (= which score constraints match for how much)
@@ -26,10 +29,10 @@ public interface ConstraintMatchAwareIncrementalScoreCalculator> getConstraintMatchTotals();
/**
@@ -44,6 +48,7 @@ public interface ConstraintMatchAwareIncrementalScoreCalculator> getIndictmentMap();
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/calculator/EasyScoreCalculator.java b/core/src/main/java/ai/timefold/solver/core/api/score/calculator/EasyScoreCalculator.java
index 7f67fda934..f9e4f94fb1 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/calculator/EasyScoreCalculator.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/calculator/EasyScoreCalculator.java
@@ -3,6 +3,8 @@
import ai.timefold.solver.core.api.domain.solution.PlanningSolution;
import ai.timefold.solver.core.api.score.Score;
+import org.jspecify.annotations.NonNull;
+
/**
* Used for easy java {@link Score} calculation. This is non-incremental calculation, which is slow.
*
@@ -17,9 +19,8 @@ public interface EasyScoreCalculator> {
* This method is only called if the {@link Score} cannot be predicted.
* The {@link Score} can be predicted for example after an undo move.
*
- * @param solution never null
- * @return never null
*/
- Score_ calculateScore(Solution_ solution);
+ @NonNull
+ Score_ calculateScore(@NonNull Solution_ solution);
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/calculator/IncrementalScoreCalculator.java b/core/src/main/java/ai/timefold/solver/core/api/score/calculator/IncrementalScoreCalculator.java
index f8e161c681..f0e25312ea 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/calculator/IncrementalScoreCalculator.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/calculator/IncrementalScoreCalculator.java
@@ -5,6 +5,8 @@
import ai.timefold.solver.core.api.domain.variable.PlanningVariable;
import ai.timefold.solver.core.api.score.Score;
+import org.jspecify.annotations.NonNull;
+
/**
* Used for incremental java {@link Score} calculation.
* This is much faster than {@link EasyScoreCalculator} but requires much more code to implement too.
@@ -19,67 +21,64 @@ public interface IncrementalScoreCalculator indictedObjectList, Score_ score) {
+ public ConstraintMatch(@NonNull ConstraintRef constraintRef, @NonNull ConstraintJustification justification,
+ @NonNull Collection indictedObjectList, @NonNull Score_ score) {
this.constraintRef = requireNonNull(constraintRef);
this.justification = requireNonNull(justification);
this.indictedObjectList =
@@ -97,7 +94,7 @@ public ConstraintMatch(ConstraintRef constraintRef, ConstraintJustification just
this.score = requireNonNull(score);
}
- public ConstraintRef getConstraintRef() {
+ public @NonNull ConstraintRef getConstraintRef() {
return constraintRef;
}
@@ -164,10 +161,8 @@ public List getJustificationList() {
* in which case it returns the return value of that function.
* For incremental score calculation, it returns what the calculator is implemented to return.
*
- *
- * @return never null
*/
- public Justification_ getJustification() {
+ public @NonNull Justification_ getJustification() {
return (Justification_) justification;
}
@@ -182,13 +177,13 @@ public Justification_ getJustif
* For incremental score calculation, it returns what the calculator is implemented to return.
*
*
- * @return never null, may be empty or contain null
+ * @return may be empty or contain null
*/
- public List getIndictedObjectList() {
+ public @NonNull List getIndictedObjectList() {
return indictedObjectList;
}
- public Score_ getScore() {
+ public @NonNull Score_ getScore() {
return score;
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/constraint/ConstraintMatchTotal.java b/core/src/main/java/ai/timefold/solver/core/api/score/constraint/ConstraintMatchTotal.java
index 667d5f6de3..5484c4f5fa 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/constraint/ConstraintMatchTotal.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/constraint/ConstraintMatchTotal.java
@@ -8,6 +8,8 @@
import ai.timefold.solver.core.api.score.ScoreExplanation;
import ai.timefold.solver.core.api.solver.SolutionManager;
+import org.jspecify.annotations.NonNull;
+
/**
* Explains the {@link Score} of a {@link PlanningSolution}, from the opposite side than {@link Indictment}.
* Retrievable from {@link ScoreExplanation#getConstraintMatchTotalMap()}.
@@ -30,9 +32,7 @@ static String composeConstraintId(String constraintPackage, String constraintNam
return constraintPackage + "/" + constraintName;
}
- /**
- * @return never null
- */
+ @NonNull
ConstraintRef getConstraintRef();
/**
@@ -57,14 +57,11 @@ default String getConstraintName() {
* The effective value of constraint weight after applying optional overrides.
* It is independent to the state of the {@link PlanningVariable planning variables}.
* Do not confuse with {@link #getScore()}.
- *
- * @return never null
*/
+ @NonNull
Score_ getConstraintWeight();
- /**
- * @return never null
- */
+ @NonNull
Set> getConstraintMatchSet();
/**
@@ -76,9 +73,8 @@ default int getConstraintMatchCount() {
/**
* Sum of the {@link #getConstraintMatchSet()}'s {@link ConstraintMatch#getScore()}.
- *
- * @return never null
*/
+ @NonNull
Score_ getScore();
/**
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/constraint/ConstraintRef.java b/core/src/main/java/ai/timefold/solver/core/api/score/constraint/ConstraintRef.java
index 3f8ba66e2e..5657951e8c 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/constraint/ConstraintRef.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/constraint/ConstraintRef.java
@@ -5,6 +5,8 @@
import ai.timefold.solver.core.api.domain.constraintweight.ConstraintConfiguration;
import ai.timefold.solver.core.api.domain.constraintweight.ConstraintWeight;
+import org.jspecify.annotations.NonNull;
+
/**
* Represents a unique identifier of a constraint.
*
@@ -23,7 +25,7 @@
* it is equal to the {@link ConstraintWeight#value()}.
* @param constraintId Always derived from {@code packageName} and {@code constraintName}.
*/
-public record ConstraintRef(String packageName, String constraintName, String constraintId)
+public record ConstraintRef(@NonNull String packageName, @NonNull String constraintName, String constraintId)
implements
Comparable {
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/constraint/Indictment.java b/core/src/main/java/ai/timefold/solver/core/api/score/constraint/Indictment.java
index 07fd6ebab5..45644647b3 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/constraint/Indictment.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/constraint/Indictment.java
@@ -9,6 +9,8 @@
import ai.timefold.solver.core.api.score.ScoreExplanation;
import ai.timefold.solver.core.api.score.stream.ConstraintJustification;
+import org.jspecify.annotations.NonNull;
+
/**
* Explains the {@link Score} of a {@link PlanningSolution}, from the opposite side than {@link ConstraintMatchTotal}.
* Retrievable from {@link ScoreExplanation#getIndictmentMap()}.
@@ -36,14 +38,11 @@ default Object getJustification() {
* It is part of {@link ConstraintMatch#getIndictedObjectList()} of every {@link ConstraintMatch}
* returned by {@link #getConstraintMatchSet()}.
*
- * @return never null
* @param Shorthand so that the user does not need to cast in user code.
*/
- IndictedObject_ getIndictedObject();
+ @NonNull IndictedObject_ getIndictedObject();
- /**
- * @return never null
- */
+ @NonNull
Set> getConstraintMatchSet();
/**
@@ -59,8 +58,9 @@ default int getConstraintMatchCount() {
* This is equivalent to retrieving {@link #getConstraintMatchSet()}
* and collecting all {@link ConstraintMatch#getJustification()} objects into a list.
*
- * @return never null, guaranteed to contain unique instances
+ * @return guaranteed to contain unique instances
*/
+ @NonNull
List getJustificationList();
/**
@@ -69,8 +69,9 @@ default int getConstraintMatchCount() {
* This is equivalent to retrieving {@link #getConstraintMatchSet()}
* and collecting all matching {@link ConstraintMatch#getJustification()} objects into a list.
*
- * @return never null, guaranteed to contain unique instances
+ * @return guaranteed to contain unique instances
*/
+ @NonNull
default List
getJustificationList(Class justificationClass) {
return getJustificationList()
@@ -82,9 +83,8 @@ default int getConstraintMatchCount() {
/**
* Sum of the {@link #getConstraintMatchSet()}'s {@link ConstraintMatch#getScore()}.
- *
- * @return never null
*/
+ @NonNull
Score_ getScore();
}
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 67ce0651e8..02df8237e1 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
@@ -6,6 +6,9 @@
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.Nullable;
+
/**
* The ScoreDirector holds the {@link PlanningSolution working solution}
* and calculates the {@link Score} for it.
@@ -19,9 +22,8 @@ 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.
- *
- * @return never null
*/
+ @NonNull
Solution_ getWorkingSolution();
void beforeVariableChanged(Object entity, String variableName);
@@ -140,14 +142,13 @@ default void afterProblemFactRemoved(Object problemFact) {
* Matching is determined by the {@link LookUpStrategyType} on {@link PlanningSolution}.
* Matching uses a {@link PlanningId} by default.
*
- * @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
*/
- E lookUpWorkingObject(E externalObject);
+ @Nullable E lookUpWorkingObject(@Nullable E externalObject);
/**
* As defined by {@link #lookUpWorkingObject(Object)},
@@ -155,12 +156,11 @@ default void afterProblemFactRemoved(Object problemFact) {
* It's recommended to use {@link #lookUpWorkingObject(Object)} instead,
* especially in move rebasing code.
*
- * @param externalObject sometimes null
* @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
*/
- E lookUpWorkingObjectOrReturnNull(E externalObject);
+ @Nullable E lookUpWorkingObjectOrReturnNull(@Nullable E externalObject);
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/stream/Constraint.java b/core/src/main/java/ai/timefold/solver/core/api/score/stream/Constraint.java
index fc6783e09a..4da1be1641 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/stream/Constraint.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/stream/Constraint.java
@@ -3,6 +3,9 @@
import ai.timefold.solver.core.api.score.Score;
import ai.timefold.solver.core.api.score.constraint.ConstraintRef;
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
/**
* This represents a single constraint in the {@link ConstraintStream} API
* that impacts the {@link Score}.
@@ -28,13 +31,13 @@ public interface Constraint {
* Returns a human-friendly description of the constraint.
* The format of the description is left unspecified and will not be parsed in any way.
*
- * @return never null, may be left empty
+ * @return may be left empty
*/
- default String getDescription() {
+ default @NonNull String getDescription() {
return "";
}
- default String getConstraintGroup() {
+ default @NonNull String getConstraintGroup() {
return DEFAULT_CONSTRAINT_GROUP;
}
@@ -44,7 +47,7 @@ default String getConstraintGroup() {
*
* @return null if the constraint does not have a weight defined
*/
- default > Score_ getConstraintWeight() {
+ default > @Nullable Score_ getConstraintWeight() {
return null;
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintBuilder.java b/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintBuilder.java
index bada819427..542a8a8ef4 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintBuilder.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintBuilder.java
@@ -4,6 +4,8 @@
import ai.timefold.solver.core.api.score.constraint.ConstraintMatchTotal;
import ai.timefold.solver.core.api.score.constraint.ConstraintRef;
+import org.jspecify.annotations.NonNull;
+
public interface ConstraintBuilder {
/**
@@ -11,10 +13,9 @@ public interface ConstraintBuilder {
* The {@link ConstraintRef#packageName() constraint package} defaults to the package of the {@link PlanningSolution} class.
* The constraint will be placed in the {@link Constraint#DEFAULT_CONSTRAINT_GROUP default constraint group}.
*
- * @param constraintName never null, shows up in {@link ConstraintMatchTotal} during score justification
- * @return never null
+ * @param constraintName shows up in {@link ConstraintMatchTotal} during score justification
*/
- default Constraint asConstraint(String constraintName) {
+ default @NonNull Constraint asConstraint(@NonNull String constraintName) {
return asConstraintDescribed(constraintName, "");
}
@@ -23,11 +24,10 @@ default Constraint asConstraint(String constraintName) {
* The {@link ConstraintRef#packageName() constraint package} defaults to the package of the {@link PlanningSolution} class.
* The constraint will be placed in the {@link Constraint#DEFAULT_CONSTRAINT_GROUP default constraint group}.
*
- * @param constraintName never null, shows up in {@link ConstraintMatchTotal} during score justification
- * @param constraintDescription never null
- * @return never null
+ * @param constraintName shows up in {@link ConstraintMatchTotal} during score justification
*/
- default Constraint asConstraintDescribed(String constraintName, String constraintDescription) {
+ @NonNull
+ default Constraint asConstraintDescribed(@NonNull String constraintName, @NonNull String constraintDescription) {
return asConstraintDescribed(constraintName, constraintDescription, Constraint.DEFAULT_CONSTRAINT_GROUP);
}
@@ -35,12 +35,12 @@ default Constraint asConstraintDescribed(String constraintName, String constrain
* Builds a {@link Constraint} from the constraint stream.
* The {@link ConstraintRef#packageName() constraint package} defaults to the package of the {@link PlanningSolution} class.
*
- * @param constraintName never null, shows up in {@link ConstraintMatchTotal} during score justification
- * @param constraintDescription never null
- * @param constraintGroup never null, only allows alphanumeric characters, "-" and "_"
- * @return never null
+ * @param constraintName shows up in {@link ConstraintMatchTotal} during score justification
+ * @param constraintGroup only allows alphanumeric characters, "-" and "_"
*/
- Constraint asConstraintDescribed(String constraintName, String constraintDescription, String constraintGroup);
+ @NonNull
+ Constraint asConstraintDescribed(@NonNull String constraintName, @NonNull String constraintDescription,
+ @NonNull String constraintGroup);
/**
* Builds a {@link Constraint} from the constraint stream.
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintCollectors.java b/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintCollectors.java
index ae36796f77..fc0137cfe0 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintCollectors.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintCollectors.java
@@ -51,6 +51,8 @@
import ai.timefold.solver.core.impl.score.stream.collector.uni.InnerUniConstraintCollectors;
import ai.timefold.solver.core.impl.util.ConstantLambdaUtils;
+import org.jspecify.annotations.NonNull;
+
/**
* Creates an {@link UniConstraintCollector}, {@link BiConstraintCollector}, ... instance
* for use in {@link UniConstraintStream#groupBy(Function, UniConstraintCollector)}, ...
@@ -69,58 +71,57 @@ public final class ConstraintCollectors {
* The default result of the collector (e.g. when never called) is {@code 0}.
*
* @param type of the matched fact
- * @return never null
*/
- public static UniConstraintCollector count() {
+ public static @NonNull UniConstraintCollector count() {
return InnerUniConstraintCollectors.count();
}
/**
* As defined by {@link #count()}.
*/
- public static UniConstraintCollector countLong() {
+ public static @NonNull UniConstraintCollector countLong() {
return InnerUniConstraintCollectors.countLong();
}
/**
* As defined by {@link #count()}.
*/
- public static BiConstraintCollector countBi() {
+ public static @NonNull BiConstraintCollector countBi() {
return InnerBiConstraintCollectors.count();
}
/**
* As defined by {@link #count()}.
*/
- public static BiConstraintCollector countLongBi() {
+ public static @NonNull BiConstraintCollector countLongBi() {
return InnerBiConstraintCollectors.countLong();
}
/**
* As defined by {@link #count()}.
*/
- public static TriConstraintCollector countTri() {
+ public static @NonNull TriConstraintCollector countTri() {
return InnerTriConstraintCollectors.count();
}
/**
* As defined by {@link #count()}.
*/
- public static TriConstraintCollector countLongTri() {
+ public static @NonNull TriConstraintCollector countLongTri() {
return InnerTriConstraintCollectors.countLong();
}
/**
* As defined by {@link #count()}.
*/
- public static QuadConstraintCollector countQuad() {
+ public static @NonNull QuadConstraintCollector countQuad() {
return InnerQuadConstraintCollectors.count();
}
/**
* As defined by {@link #count()}.
*/
- public static QuadConstraintCollector countLongQuad() {
+ public static @NonNull QuadConstraintCollector countLongQuad() {
return InnerQuadConstraintCollectors.countLong();
}
@@ -145,64 +146,63 @@ public final class ConstraintCollectors {
* The default result of the collector (e.g. when never called) is {@code 0}.
*
* @param type of the matched fact
- * @return never null
*/
- public static UniConstraintCollector countDistinct(Function groupValueMapping) {
+ public static @NonNull UniConstraintCollector countDistinct(@NonNull Function groupValueMapping) {
return InnerUniConstraintCollectors.countDistinct(groupValueMapping);
}
/**
* As defined by {@link #countDistinct(Function)}.
*/
- public static UniConstraintCollector countDistinctLong(Function groupValueMapping) {
+ public static @NonNull UniConstraintCollector countDistinctLong(@NonNull Function groupValueMapping) {
return InnerUniConstraintCollectors.countDistinctLong(groupValueMapping);
}
/**
* As defined by {@link #countDistinct(Function)}.
*/
- public static BiConstraintCollector countDistinct(
- BiFunction groupValueMapping) {
+ public static @NonNull BiConstraintCollector countDistinct(
+ @NonNull BiFunction groupValueMapping) {
return InnerBiConstraintCollectors.countDistinct(groupValueMapping);
}
/**
* As defined by {@link #countDistinct(Function)}.
*/
- public static BiConstraintCollector countDistinctLong(
- BiFunction groupValueMapping) {
+ public static @NonNull BiConstraintCollector countDistinctLong(
+ @NonNull BiFunction groupValueMapping) {
return InnerBiConstraintCollectors.countDistinctLong(groupValueMapping);
}
/**
* As defined by {@link #countDistinct(Function)}.
*/
- public static TriConstraintCollector countDistinct(
- TriFunction groupValueMapping) {
+ public static @NonNull TriConstraintCollector countDistinct(
+ @NonNull TriFunction groupValueMapping) {
return InnerTriConstraintCollectors.countDistinct(groupValueMapping);
}
/**
* As defined by {@link #countDistinct(Function)}.
*/
- public static TriConstraintCollector countDistinctLong(
- TriFunction groupValueMapping) {
+ public static @NonNull TriConstraintCollector countDistinctLong(
+ @NonNull TriFunction groupValueMapping) {
return InnerTriConstraintCollectors.countDistinctLong(groupValueMapping);
}
/**
* As defined by {@link #countDistinct(Function)}.
*/
- public static QuadConstraintCollector countDistinct(
- QuadFunction groupValueMapping) {
+ public static @NonNull QuadConstraintCollector countDistinct(
+ @NonNull QuadFunction groupValueMapping) {
return InnerQuadConstraintCollectors.countDistinct(groupValueMapping);
}
/**
* As defined by {@link #countDistinct(Function)}.
*/
- public static QuadConstraintCollector countDistinctLong(
- QuadFunction groupValueMapping) {
+ public static @NonNull QuadConstraintCollector countDistinctLong(
+ @NonNull QuadFunction groupValueMapping) {
return InnerQuadConstraintCollectors.countDistinctLong(groupValueMapping);
}
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 9c3a80a79e..e7804ebbac 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
@@ -14,6 +14,8 @@
import ai.timefold.solver.core.api.score.stream.bi.BiJoiner;
import ai.timefold.solver.core.api.score.stream.uni.UniConstraintStream;
+import org.jspecify.annotations.NonNull;
+
/**
* The factory to create every {@link ConstraintStream} (for example with {@link #forEach(Class)})
* which ends in a {@link Constraint} returned by {@link ConstraintProvider#defineConstraints(ConstraintFactory)}.
@@ -21,10 +23,10 @@
public interface ConstraintFactory {
/**
- * @return never null
* @deprecated Do not rely on any constraint package in user code.
*/
@Deprecated(forRemoval = true, since = "1.13.0")
+ @NonNull
String getDefaultConstraintPackage();
// ************************************************************************
@@ -59,19 +61,17 @@ public interface ConstraintFactory {
* Adding the field is strongly recommended.
*
*
- * @param sourceClass never null
* @param the type of the matched problem fact or {@link PlanningEntity planning entity}
- * @return never null
*/
- UniConstraintStream forEach(Class sourceClass);
+ @NonNull UniConstraintStream forEach(@NonNull Class sourceClass);
/**
* As defined by {@link #forEachIncludingUnassigned(Class)}.
- *
+ *
* @deprecated Use {@link #forEachIncludingUnassigned(Class)} instead.
*/
@Deprecated(forRemoval = true, since = "1.8.0")
- default UniConstraintStream forEachIncludingNullVars(Class sourceClass) {
+ default @NonNull UniConstraintStream forEachIncludingNullVars(@NonNull Class sourceClass) {
return forEachIncludingUnassigned(sourceClass);
}
@@ -82,11 +82,9 @@ default UniConstraintStream forEachIncludingNullVars(Class sourceClass
* or shadow entities not assigned to any applicable list variable
* (for {@link PlanningListVariable#allowsUnassignedValues()}).
*
- * @param sourceClass never null
* @param the type of the matched problem fact or {@link PlanningEntity planning entity}
- * @return never null
*/
- UniConstraintStream forEachIncludingUnassigned(Class sourceClass);
+ @NonNull UniConstraintStream forEachIncludingUnassigned(@NonNull Class sourceClass);
/**
* Create a new {@link BiConstraintStream} for every unique combination of A and another A with a higher {@link PlanningId}.
@@ -99,11 +97,10 @@ default UniConstraintStream forEachIncludingNullVars(Class sourceClass
* This method is syntactic sugar for {@link UniConstraintStream#join(Class)}.
* It automatically adds a {@link Joiners#lessThan(Function) lessThan} joiner on the {@link PlanningId} of A.
*
- * @param sourceClass never null
* @param the type of the matched problem fact or {@link PlanningEntity planning entity}
* @return a stream that matches every unique combination of A and another A
*/
- default BiConstraintStream forEachUniquePair(Class sourceClass) {
+ default @NonNull BiConstraintStream forEachUniquePair(@NonNull Class sourceClass) {
return forEachUniquePair(sourceClass, new BiJoiner[0]);
}
@@ -121,60 +118,50 @@ default BiConstraintStream forEachUniquePair(Class sourceClass) {
*
* This method has overloaded methods with multiple {@link BiJoiner} parameters.
*
- * @param sourceClass never null
- * @param joiner never null
* @param the type of the matched problem fact or {@link PlanningEntity planning entity}
* @return a stream that matches every unique combination of A and another A for which the {@link BiJoiner} is true
*/
- default BiConstraintStream forEachUniquePair(Class sourceClass, BiJoiner joiner) {
+ default @NonNull BiConstraintStream forEachUniquePair(@NonNull Class sourceClass,
+ @NonNull BiJoiner joiner) {
return forEachUniquePair(sourceClass, new BiJoiner[] { joiner });
}
/**
* As defined by {@link #forEachUniquePair(Class, BiJoiner)}.
*
- * @param sourceClass never null
- * @param joiner1 never null
- * @param joiner2 never null
* @param the type of the matched problem fact or {@link PlanningEntity planning entity}
* @return a stream that matches every unique combination of A and another A for which all the
* {@link BiJoiner joiners} are true
*/
- default BiConstraintStream forEachUniquePair(Class sourceClass, BiJoiner joiner1,
- BiJoiner joiner2) {
+ default @NonNull BiConstraintStream forEachUniquePair(@NonNull Class sourceClass,
+ @NonNull BiJoiner joiner1,
+ @NonNull BiJoiner joiner2) {
return forEachUniquePair(sourceClass, new BiJoiner[] { joiner1, joiner2 });
}
/**
* As defined by {@link #forEachUniquePair(Class, BiJoiner)}.
*
- * @param sourceClass never null
- * @param joiner1 never null
- * @param joiner2 never null
- * @param joiner3 never null
* @param the type of the matched problem fact or {@link PlanningEntity planning entity}
* @return a stream that matches every unique combination of A and another A for which all the
* {@link BiJoiner joiners} are true
*/
- default BiConstraintStream forEachUniquePair(Class sourceClass, BiJoiner joiner1, BiJoiner joiner2,
- BiJoiner joiner3) {
+ default @NonNull BiConstraintStream forEachUniquePair(@NonNull Class sourceClass,
+ @NonNull BiJoiner joiner1, @NonNull BiJoiner joiner2,
+ @NonNull BiJoiner joiner3) {
return forEachUniquePair(sourceClass, new BiJoiner[] { joiner1, joiner2, joiner3 });
}
/**
* As defined by {@link #forEachUniquePair(Class, BiJoiner)}.
*
- * @param sourceClass never null
- * @param joiner1 never null
- * @param joiner2 never null
- * @param joiner3 never null
- * @param joiner4 never null
* @param the type of the matched problem fact or {@link PlanningEntity planning entity}
* @return a stream that matches every unique combination of A and another A for which all the
* {@link BiJoiner joiners} are true
*/
- default BiConstraintStream forEachUniquePair(Class sourceClass, BiJoiner joiner1, BiJoiner joiner2,
- BiJoiner joiner3, BiJoiner joiner4) {
+ default @NonNull BiConstraintStream forEachUniquePair(@NonNull Class sourceClass,
+ @NonNull BiJoiner joiner1, @NonNull BiJoiner joiner2,
+ @NonNull BiJoiner joiner3, @NonNull BiJoiner joiner4) {
return forEachUniquePair(sourceClass, new BiJoiner[] { joiner1, joiner2, joiner3, joiner4 });
}
@@ -185,13 +172,11 @@ default BiConstraintStream forEachUniquePair(Class sourceClass, BiJ
* but we can't fix it with a {@link SafeVarargs} annotation because it's an interface method.
* Therefore, there are overloaded methods with up to 4 {@link BiJoiner} parameters.
*
- * @param sourceClass never null
- * @param joiners never null
* @param the type of the matched problem fact or {@link PlanningEntity planning entity}
* @return a stream that matches every unique combination of A and another A for which all the
* {@link BiJoiner joiners} are true
*/
- BiConstraintStream forEachUniquePair(Class sourceClass, BiJoiner ... joiners);
+ @NonNull BiConstraintStream forEachUniquePair(@NonNull Class sourceClass, @NonNull BiJoiner ... joiners);
// ************************************************************************
// from* (deprecated)
@@ -227,15 +212,13 @@ default BiConstraintStream forEachUniquePair(Class sourceClass, BiJ
* for which each genuine {@link PlanningVariable} (of the fromClass or a superclass thereof) is initialized.
* This filtering will NOT automatically apply to genuine planning variables of subclass planning entities of the fromClass.
*
+ * @param the type of the matched problem fact or {@link PlanningEntity planning entity}
* @deprecated This method is deprecated in favor of {@link #forEach(Class)},
* which exhibits the same behavior for planning variables
* which both allow and don't allow unassigned values.
- * @param fromClass never null
- * @param the type of the matched problem fact or {@link PlanningEntity planning entity}
- * @return never null
*/
@Deprecated(forRemoval = true)
- UniConstraintStream from(Class fromClass);
+ @NonNull UniConstraintStream from(@NonNull Class fromClass);
/**
* This method is deprecated.
@@ -249,13 +232,12 @@ default BiConstraintStream forEachUniquePair(Class sourceClass, BiJ
* As defined by {@link #from(Class)},
* but without any filtering of uninitialized {@link PlanningEntity planning entities}.
*
- * @deprecated Prefer {@link #forEachIncludingUnassigned(Class)}.
- * @param fromClass never null
* @param the type of the matched problem fact or {@link PlanningEntity planning entity}
- * @return never null
+ * @deprecated Prefer {@link #forEachIncludingUnassigned(Class)}.
*/
@Deprecated(forRemoval = true)
- UniConstraintStream fromUnfiltered(Class fromClass);
+ @NonNull
+ UniConstraintStream fromUnfiltered(@NonNull Class fromClass);
/**
* This method is deprecated.
@@ -277,12 +259,11 @@ default BiConstraintStream forEachUniquePair(Class sourceClass, BiJ
* @deprecated Prefer {@link #forEachUniquePair(Class)},
* which exhibits the same behavior for planning variables
* which both allow and don't allow unassigned values.
- * @param fromClass never null
* @param the type of the matched problem fact or {@link PlanningEntity planning entity}
* @return a stream that matches every unique combination of A and another A
*/
@Deprecated(forRemoval = true)
- default BiConstraintStream fromUniquePair(Class fromClass) {
+ default @NonNull BiConstraintStream fromUniquePair(@NonNull Class fromClass) {
return fromUniquePair(fromClass, new BiJoiner[0]);
}
@@ -309,13 +290,11 @@ default BiConstraintStream fromUniquePair(Class fromClass) {
* @deprecated Prefer {@link #forEachUniquePair(Class, BiJoiner)},
* which exhibits the same behavior for planning variables
* which both allow and don't allow unassigned values.
- * @param fromClass never null
- * @param joiner never null
* @param the type of the matched problem fact or {@link PlanningEntity planning entity}
* @return a stream that matches every unique combination of A and another A for which the {@link BiJoiner} is true
*/
@Deprecated(forRemoval = true)
- default BiConstraintStream fromUniquePair(Class fromClass, BiJoiner joiner) {
+ default @NonNull BiConstraintStream fromUniquePair(@NonNull Class fromClass, @NonNull BiJoiner joiner) {
return fromUniquePair(fromClass, new BiJoiner[] { joiner });
}
@@ -331,15 +310,13 @@ default BiConstraintStream fromUniquePair(Class fromClass, BiJoiner
* @deprecated Prefer {@link #forEachUniquePair(Class, BiJoiner, BiJoiner)},
* which exhibits the same behavior for planning variables
* which both allow and don't allow unassigned values.
- * @param fromClass never null
- * @param joiner1 never null
- * @param joiner2 never null
* @param the type of the matched problem fact or {@link PlanningEntity planning entity}
* @return a stream that matches every unique combination of A and another A for which all the
* {@link BiJoiner joiners} are true
*/
@Deprecated(forRemoval = true)
- default BiConstraintStream fromUniquePair(Class fromClass, BiJoiner joiner1, BiJoiner joiner2) {
+ default @NonNull BiConstraintStream fromUniquePair(@NonNull Class fromClass, @NonNull BiJoiner joiner1,
+ @NonNull BiJoiner joiner2) {
return fromUniquePair(fromClass, new BiJoiner[] { joiner1, joiner2 });
}
@@ -355,17 +332,14 @@ default BiConstraintStream fromUniquePair(Class fromClass, BiJoiner
* @deprecated Prefer {@link #forEachUniquePair(Class, BiJoiner, BiJoiner, BiJoiner)},
* which exhibits the same behavior for planning variables
* which both allow and don't allow unassigned values.
- * @param fromClass never null
- * @param joiner1 never null
- * @param joiner2 never null
- * @param joiner3 never null
+ *
* @param the type of the matched problem fact or {@link PlanningEntity planning entity}
* @return a stream that matches every unique combination of A and another A for which all the
* {@link BiJoiner joiners} are true
*/
@Deprecated(forRemoval = true)
- default BiConstraintStream fromUniquePair(Class fromClass, BiJoiner joiner1, BiJoiner joiner2,
- BiJoiner joiner3) {
+ default @NonNull BiConstraintStream fromUniquePair(@NonNull Class fromClass, @NonNull BiJoiner joiner1,
+ @NonNull BiJoiner joiner2, @NonNull BiJoiner joiner3) {
return fromUniquePair(fromClass, new BiJoiner[] { joiner1, joiner2, joiner3 });
}
@@ -378,21 +352,17 @@ default BiConstraintStream fromUniquePair(Class fromClass, BiJoiner
*
* As defined by {@link #fromUniquePair(Class, BiJoiner)}.
*
- * @deprecated Prefer {@link #forEachUniquePair(Class, BiJoiner, BiJoiner, BiJoiner, BiJoiner)},
- * which exhibits the same behavior for planning variables
- * which both allow and don't allow unassigned values.
- * @param fromClass never null
- * @param joiner1 never null
- * @param joiner2 never null
- * @param joiner3 never null
- * @param joiner4 never null
* @param the type of the matched problem fact or {@link PlanningEntity planning entity}
* @return a stream that matches every unique combination of A and another A for which all the
* {@link BiJoiner joiners} are true
+ * @deprecated Prefer {@link #forEachUniquePair(Class, BiJoiner, BiJoiner, BiJoiner, BiJoiner)},
+ * which exhibits the same behavior for planning variables
+ * which both allow and don't allow unassigned values.
*/
@Deprecated(forRemoval = true)
- default BiConstraintStream fromUniquePair(Class fromClass, BiJoiner joiner1, BiJoiner joiner2,
- BiJoiner joiner3, BiJoiner joiner4) {
+ default @NonNull BiConstraintStream fromUniquePair(@NonNull Class fromClass,
+ @NonNull BiJoiner joiner1, @NonNull BiJoiner joiner2,
+ @NonNull BiJoiner joiner3, @NonNull BiJoiner joiner4) {
return fromUniquePair(fromClass, new BiJoiner[] { joiner1, joiner2, joiner3, joiner4 });
}
@@ -409,16 +379,15 @@ default BiConstraintStream fromUniquePair(Class fromClass, BiJoiner
* but we can't fix it with a {@link SafeVarargs} annotation because it's an interface method.
* Therefore, there are overloaded methods with up to 4 {@link BiJoiner} parameters.
*
- * @deprecated Prefer {@link #forEachUniquePair(Class, BiJoiner...)},
- * which exhibits the same behavior for planning variables
- * which both allow and don't allow unassigned values.
- * @param fromClass never null
- * @param joiners never null
* @param the type of the matched problem fact or {@link PlanningEntity planning entity}
* @return a stream that matches every unique combination of A and another A for which all the
* {@link BiJoiner joiners} are true
+ * @deprecated Prefer {@link #forEachUniquePair(Class, BiJoiner...)},
+ * which exhibits the same behavior for planning variables
+ * which both allow and don't allow unassigned values.
*/
@Deprecated(forRemoval = true)
- BiConstraintStream fromUniquePair(Class fromClass, BiJoiner ... joiners);
+ @NonNull
+ BiConstraintStream fromUniquePair(@NonNull Class fromClass, @NonNull BiJoiner ... joiners);
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintMetaModel.java b/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintMetaModel.java
index b83bfb818d..d9a87e3f70 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintMetaModel.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintMetaModel.java
@@ -5,6 +5,9 @@
import ai.timefold.solver.core.api.score.constraint.ConstraintRef;
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
/**
* Provides information about the known constraints.
* Works in combination with {@link ConstraintProvider}.
@@ -14,31 +17,33 @@ public interface ConstraintMetaModel {
/**
* Returns the constraint for the given reference.
*
- * @param constraintRef never null
* @return null if such constraint does not exist
*/
- Constraint getConstraint(ConstraintRef constraintRef);
+ @Nullable
+ Constraint getConstraint(@NonNull ConstraintRef constraintRef);
/**
* Returns all constraints defined in the {@link ConstraintProvider}.
*
- * @return never null, iteration order is undefined
+ * @return iteration order is undefined
*/
+ @NonNull
Collection getConstraints();
/**
* Returns all constraints from {@link #getConstraints()} that belong to the given group.
*
- * @param constraintGroup never null
- * @return never null, iteration order is undefined
+ * @return iteration order is undefined
*/
- Collection getConstraintsPerGroup(String constraintGroup);
+ @NonNull
+ Collection getConstraintsPerGroup(@NonNull String constraintGroup);
/**
* Returns constraint groups with at least one constraint in it.
*
- * @return never null, iteration order is undefined
+ * @return iteration order is undefined
*/
+ @NonNull
Set getConstraintGroups();
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintProvider.java b/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintProvider.java
index 95aacd5046..0b12378b81 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintProvider.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintProvider.java
@@ -3,6 +3,8 @@
import ai.timefold.solver.core.api.domain.constraintweight.ConstraintWeight;
import ai.timefold.solver.core.api.score.Score;
+import org.jspecify.annotations.NonNull;
+
/**
* Used by Constraint Streams' {@link Score} calculation.
* An implementation must be stateless in order to facilitate building a single set of constraints
@@ -14,11 +16,10 @@ public interface ConstraintProvider {
* This method is called once to create the constraints.
* To create a {@link Constraint}, start with {@link ConstraintFactory#forEach(Class)}.
*
- * @param constraintFactory never null
* @return an array of all {@link Constraint constraints} that could apply.
* The constraints with a zero {@link ConstraintWeight} for a particular problem
* will be automatically disabled when scoring that problem, to improve performance.
*/
- Constraint[] defineConstraints(ConstraintFactory constraintFactory);
+ Constraint @NonNull [] defineConstraints(@NonNull ConstraintFactory constraintFactory);
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintStream.java b/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintStream.java
index eb50643a0a..e4c9e525c9 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintStream.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/stream/ConstraintStream.java
@@ -17,6 +17,8 @@
import ai.timefold.solver.core.api.score.stream.uni.UniConstraintStream;
import ai.timefold.solver.core.api.solver.SolutionManager;
+import org.jspecify.annotations.NonNull;
+
/**
* A constraint stream is a declaration on how to match {@link UniConstraintStream one}, {@link BiConstraintStream two}
* or more objects.
@@ -72,9 +74,8 @@ public interface ConstraintStream {
/**
* The {@link ConstraintFactory} that build this.
- *
- * @return never null
*/
+ @NonNull
ConstraintFactory getConstraintFactory();
// ************************************************************************
@@ -90,24 +91,20 @@ public interface ConstraintStream {
* The {@link ConstraintRef#packageName() constraint package} defaults to the package of the {@link PlanningSolution} class.
*
* @deprecated Prefer {@link UniConstraintStream#penalize(Score)} and equivalent bi/tri/... overloads.
- * @param constraintName never null, shows up in {@link ConstraintMatchTotal} during score justification
- * @param constraintWeight never null
- * @return never null
+ * @param constraintName shows up in {@link ConstraintMatchTotal} during score justification
*/
@Deprecated(forRemoval = true)
- Constraint penalize(String constraintName, Score> constraintWeight);
+ @NonNull
+ Constraint penalize(@NonNull String constraintName, @NonNull Score> constraintWeight);
/**
* As defined by {@link #penalize(String, Score)}.
*
* @deprecated Prefer {@link UniConstraintStream#penalize(Score)} and equivalent bi/tri/... overloads.
- * @param constraintPackage never null
- * @param constraintName never null
- * @param constraintWeight never null
- * @return never null
*/
@Deprecated(forRemoval = true)
- Constraint penalize(String constraintPackage, String constraintName, Score> constraintWeight);
+ @NonNull
+ Constraint penalize(@NonNull String constraintPackage, @NonNull String constraintName, @NonNull Score> constraintWeight);
/**
* Negatively impact the {@link Score}: subtract the {@link ConstraintWeight} for each match.
@@ -119,23 +116,21 @@ public interface ConstraintStream {
* The {@link ConstraintRef#packageName() constraint package} defaults to
* {@link ConstraintConfiguration#constraintPackage()}.
*
- * @param constraintName never null, shows up in {@link ConstraintMatchTotal} during score justification
- * @return never null
+ * @param constraintName shows up in {@link ConstraintMatchTotal} during score justification
* @deprecated Prefer {@code penalize()} and {@link ConstraintWeightOverrides}.
*/
@Deprecated(forRemoval = true)
- Constraint penalizeConfigurable(String constraintName);
+ @NonNull
+ Constraint penalizeConfigurable(@NonNull String constraintName);
/**
* As defined by {@link #penalizeConfigurable(String)}.
*
- * @param constraintPackage never null
- * @param constraintName never null
- * @return never null
* @deprecated Prefer {@code penalize()} and {@link ConstraintWeightOverrides}.
*/
@Deprecated(forRemoval = true)
- Constraint penalizeConfigurable(String constraintPackage, String constraintName);
+ @NonNull
+ Constraint penalizeConfigurable(@NonNull String constraintPackage, @NonNull String constraintName);
/**
* Positively impact the {@link Score}: add the constraintWeight for each match.
@@ -146,24 +141,20 @@ public interface ConstraintStream {
* The {@link ConstraintRef#packageName() constraint package} defaults to the package of the {@link PlanningSolution} class.
*
* @deprecated Prefer {@link UniConstraintStream#reward(Score)} and equivalent bi/tri/... overloads.
- * @param constraintName never null, shows up in {@link ConstraintMatchTotal} during score justification
- * @param constraintWeight never null
- * @return never null
+ * @param constraintName shows up in {@link ConstraintMatchTotal} during score justification
*/
@Deprecated(forRemoval = true)
- Constraint reward(String constraintName, Score> constraintWeight);
+ @NonNull
+ Constraint reward(@NonNull String constraintName, @NonNull Score> constraintWeight);
/**
* As defined by {@link #reward(String, Score)}.
*
* @deprecated Prefer {@link UniConstraintStream#reward(Score)} and equivalent bi/tri/... overloads.
- * @param constraintPackage never null
- * @param constraintName never null
- * @param constraintWeight never null
- * @return never null
*/
@Deprecated(forRemoval = true)
- Constraint reward(String constraintPackage, String constraintName, Score> constraintWeight);
+ @NonNull
+ Constraint reward(@NonNull String constraintPackage, @NonNull String constraintName, @NonNull Score> constraintWeight);
/**
* Positively impact the {@link Score}: add the {@link ConstraintWeight} for each match.
@@ -175,23 +166,21 @@ public interface ConstraintStream {
* The {@link ConstraintRef#packageName() constraint package} defaults to
* {@link ConstraintConfiguration#constraintPackage()}.
*
- * @param constraintName never null, shows up in {@link ConstraintMatchTotal} during score justification
- * @return never null
+ * @param constraintName shows up in {@link ConstraintMatchTotal} during score justification
* @deprecated Prefer {@code reward()} and {@link ConstraintWeightOverrides}.
*/
@Deprecated(forRemoval = true)
- Constraint rewardConfigurable(String constraintName);
+ @NonNull
+ Constraint rewardConfigurable(@NonNull String constraintName);
/**
* As defined by {@link #rewardConfigurable(String)}.
*
- * @param constraintPackage never null
- * @param constraintName never null
- * @return never null
* @deprecated Prefer {@code reward()} and {@link ConstraintWeightOverrides}.
*/
@Deprecated(forRemoval = true)
- Constraint rewardConfigurable(String constraintPackage, String constraintName);
+ @NonNull
+ Constraint rewardConfigurable(@NonNull String constraintPackage, @NonNull String constraintName);
/**
* Positively or negatively impact the {@link Score} by the constraintWeight for each match.
@@ -202,23 +191,19 @@ public interface ConstraintStream {
* The {@link ConstraintRef#packageName() constraint package} defaults to the package of the {@link PlanningSolution} class.
*
* @deprecated Prefer {@link UniConstraintStream#impact(Score)} and equivalent bi/tri/... overloads.
- * @param constraintName never null, shows up in {@link ConstraintMatchTotal} during score justification
- * @param constraintWeight never null
- * @return never null
+ * @param constraintName shows up in {@link ConstraintMatchTotal} during score justification
*/
@Deprecated(forRemoval = true)
- Constraint impact(String constraintName, Score> constraintWeight);
+ @NonNull
+ Constraint impact(@NonNull String constraintName, @NonNull Score> constraintWeight);
/**
* As defined by {@link #impact(String, Score)}.
*
* @deprecated Prefer {@link UniConstraintStream#impact(Score)} and equivalent bi/tri/... overloads.
- * @param constraintPackage never null
- * @param constraintName never null
- * @param constraintWeight never null
- * @return never null
*/
@Deprecated(forRemoval = true)
- Constraint impact(String constraintPackage, String constraintName, Score> constraintWeight);
+ @NonNull
+ Constraint impact(@NonNull String constraintPackage, @NonNull String constraintName, @NonNull Score> constraintWeight);
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/stream/DefaultConstraintJustification.java b/core/src/main/java/ai/timefold/solver/core/api/score/stream/DefaultConstraintJustification.java
index dcbd16f4c8..c22d9f90da 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/stream/DefaultConstraintJustification.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/stream/DefaultConstraintJustification.java
@@ -8,6 +8,9 @@
import ai.timefold.solver.core.api.score.Score;
import ai.timefold.solver.core.api.score.constraint.ConstraintMatch;
+import org.jspecify.annotations.NonNull;
+import org.jspecify.annotations.Nullable;
+
/**
* Default implementation of {@link ConstraintJustification}, returned by {@link ConstraintMatch#getJustification()}
* unless the user defined a custom justification mapping.
@@ -15,27 +18,28 @@
public final class DefaultConstraintJustification
implements ConstraintJustification, Comparable {
- public static DefaultConstraintJustification of(Score> impact, Object fact) {
+ public static @NonNull DefaultConstraintJustification of(Score> impact, Object fact) {
return of(impact, Collections.singletonList(fact));
}
- public static DefaultConstraintJustification of(Score> impact, Object factA, Object factB) {
+ public static @NonNull DefaultConstraintJustification of(Score> impact, Object factA, Object factB) {
return of(impact, Arrays.asList(factA, factB));
}
- public static DefaultConstraintJustification of(Score> impact, Object factA, Object factB, Object factC) {
+ public static @NonNull DefaultConstraintJustification of(Score> impact, Object factA, Object factB, Object factC) {
return of(impact, Arrays.asList(factA, factB, factC));
}
- public static DefaultConstraintJustification of(Score> impact, Object factA, Object factB, Object factC, Object factD) {
+ public static @NonNull DefaultConstraintJustification of(Score> impact, Object factA, Object factB, Object factC,
+ Object factD) {
return of(impact, Arrays.asList(factA, factB, factC, factD));
}
- public static DefaultConstraintJustification of(Score> impact, Object... facts) {
+ public static @NonNull DefaultConstraintJustification of(Score> impact, Object... facts) {
return of(impact, Arrays.asList(facts));
}
- public static DefaultConstraintJustification of(Score> impact, List facts) {
+ public static @NonNull DefaultConstraintJustification of(Score> impact, List facts) {
return new DefaultConstraintJustification(impact, facts);
}
@@ -51,11 +55,7 @@ public > Score_ getImpact() {
return (Score_) impact;
}
- /**
- *
- * @return never null; may contain null
- */
- public List getFacts() {
+ public @NonNull List<@Nullable Object> getFacts() {
return facts;
}
diff --git a/core/src/main/java/ai/timefold/solver/core/api/score/stream/Joiners.java b/core/src/main/java/ai/timefold/solver/core/api/score/stream/Joiners.java
index 71e5ea8ff5..a2a2f11d86 100644
--- a/core/src/main/java/ai/timefold/solver/core/api/score/stream/Joiners.java
+++ b/core/src/main/java/ai/timefold/solver/core/api/score/stream/Joiners.java
@@ -26,6 +26,8 @@
import ai.timefold.solver.core.impl.score.stream.common.tri.FilteringTriJoiner;
import ai.timefold.solver.core.impl.util.ConstantLambdaUtils;
+import org.jspecify.annotations.NonNull;
+
/**
* Creates an {@link BiJoiner}, {@link TriJoiner}, ... instance
* for use in {@link UniConstraintStream#join(Class, BiJoiner)}, ...
@@ -43,9 +45,8 @@ public final class Joiners {
* As defined by {@link #equal(Function)} with {@link Function#identity()} as the argument.
*
* @param the type of both objects
- * @return never null
*/
- public static BiJoiner equal() {
+ public static @NonNull BiJoiner equal() {
return equal(ConstantLambdaUtils.identity());
}
@@ -55,9 +56,8 @@ public static BiJoiner equal() {
* @param the type of both objects
* @param the type of the property to compare
* @param mapping mapping function to apply to both A and B
- * @return never null
*/
- public static BiJoiner equal(Function mapping) {
+ public static @NonNull BiJoiner equal(Function mapping) {
return equal(mapping, mapping);
}
@@ -73,9 +73,8 @@ public static BiJoiner equal(Function mapping
* @param the type of the property to compare
* @param leftMapping mapping function to apply to A
* @param rightMapping mapping function to apply to B
- * @return never null
*/
- public static BiJoiner equal(Function leftMapping,
+ public static @NonNull BiJoiner equal(Function leftMapping,
Function rightMapping) {
return new DefaultBiJoiner<>(leftMapping, JoinerType.EQUAL, rightMapping);
}
@@ -86,9 +85,9 @@ public static BiJoiner equal(Function left
* @param mapping mapping function to apply
* @param the type of both objects
* @param the type of the property to compare
- * @return never null
*/
- public static > BiJoiner lessThan(Function mapping) {
+ public static > @NonNull BiJoiner
+ lessThan(Function mapping) {
return lessThan(mapping, mapping);
}
@@ -105,9 +104,8 @@ public static > BiJoiner lessTh
* @param the type of object on the left
* @param the type of object on the right
* @param the type of the property to compare
- * @return never null
*/
- public static > BiJoiner lessThan(
+ public static > @NonNull BiJoiner lessThan(
Function leftMapping, Function rightMapping) {
return new DefaultBiJoiner<>(leftMapping, JoinerType.LESS_THAN, rightMapping);
}
@@ -118,9 +116,8 @@ public static > BiJoiner les
* @param mapping mapping function to apply
* @param the type of both objects
* @param the type of the property to compare
- * @return never null
*/
- public static > BiJoiner lessThanOrEqual(
+ public static > @NonNull BiJoiner lessThanOrEqual(
Function mapping) {
return lessThanOrEqual(mapping, mapping);
}
@@ -139,9 +136,8 @@ public static > BiJoiner lessTh
* @param the type of object on the left
* @param the type of object on the right
* @param the type of the property to compare
- * @return never null
*/
- public static > BiJoiner lessThanOrEqual(
+ public static > @NonNull BiJoiner lessThanOrEqual(
Function leftMapping, Function rightMapping) {
return new DefaultBiJoiner<>(leftMapping, JoinerType.LESS_THAN_OR_EQUAL, rightMapping);
}
@@ -152,9 +148,8 @@ public static > BiJoiner les
* @param mapping mapping function to apply
* @param the type of both objects
* @param the type of the property to compare
- * @return never null
*/
- public static > BiJoiner greaterThan(
+ public static > @NonNull BiJoiner greaterThan(
Function mapping) {
return greaterThan(mapping, mapping);
}
@@ -172,9 +167,8 @@ public static > BiJoiner greate
* @param the type of object on the left
* @param the type of object on the right
* @param the type of the property to compare
- * @return never null
*/
- public static > BiJoiner greaterThan(
+ public static > @NonNull BiJoiner greaterThan(
Function leftMapping, Function rightMapping) {
return new DefaultBiJoiner<>(leftMapping, JoinerType.GREATER_THAN, rightMapping);
}
@@ -185,9 +179,8 @@ public static > BiJoiner gre
* @param mapping mapping function to apply
* @param the type of both objects
* @param the type of the property to compare
- * @return never null
*/
- public static > BiJoiner greaterThanOrEqual(
+ public static > @NonNull BiJoiner greaterThanOrEqual(
Function mapping) {
return greaterThanOrEqual(mapping, mapping);
}
@@ -206,9 +199,8 @@ public static > BiJoiner greate
* @param the type of object on the left
* @param the type of object on the right
* @param the type of the property to compare
- * @return never null
*/
- public static > BiJoiner greaterThanOrEqual(
+ public static > @NonNull BiJoiner greaterThanOrEqual(
Function leftMapping, Function rightMapping) {
return new DefaultBiJoiner<>(leftMapping, JoinerType.GREATER_THAN_OR_EQUAL, rightMapping);
}
@@ -220,12 +212,11 @@ public static > BiJoiner gre
* with filter being {@code age == 20},
* this joiner will produce pairs {@code (Ann, Ann), (Ann, Eric), (Eric, Ann), (Eric, Eric)}.
*
- * @param filter never null, filter to apply
+ * @param filter filter to apply
* @param type of the first fact in the tuple
* @param type of the second fact in the tuple
- * @return never null
*/
- public static BiJoiner filtering(BiPredicate filter) {
+ public static @NonNull BiJoiner filtering(@NonNull BiPredicate filter) {
return new FilteringBiJoiner<>(filter);
}
@@ -243,9 +234,8 @@ public static BiJoiner filtering(BiPredicate filter) {
* @param endMapping maps the argument to the end point of its interval (exclusive)
* @param the type of both the first and second argument
* @param the type used to define the interval, comparable
- * @return never null
*/
- public static > BiJoiner overlapping(
+ public static > @NonNull BiJoiner overlapping(
Function startMapping, Function endMapping) {
return overlapping(startMapping, endMapping, startMapping, endMapping);
}
@@ -260,9 +250,8 @@ public static > BiJoiner overla
* @param the type of the first argument
* @param the type of the second argument
* @param the type used to define the interval, comparable
- * @return never null
*/
- public static > BiJoiner overlapping(
+ public static > @NonNull BiJoiner overlapping(
Function leftStartMapping, Function leftEndMapping,
Function rightStartMapping, Function rightEndMapping) {
return Joiners.lessThan(leftStartMapping, rightEndMapping)
@@ -282,9 +271,8 @@ public static > BiJoiner ove
* @param the type of the property to compare
* @param leftMapping mapping function to apply to (A,B)
* @param rightMapping mapping function to apply to C
- * @return never null
*/
- public static TriJoiner equal(BiFunction leftMapping,
+ public static @NonNull TriJoiner equal(BiFunction leftMapping,
Function