Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Do not throw an exception when the solution or entity classes are interfaces #934

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ public static int resolvePoolSize(String propertyName, String value, String... m

public static List<Class<?>> getAllAnnotatedLineageClasses(Class<?> bottomClass,
Class<? extends Annotation> annotation) {
if (!bottomClass.isAnnotationPresent(annotation)) {
if (bottomClass == null || !bottomClass.isAnnotationPresent(annotation)) {
return Collections.emptyList();
}
List<Class<?>> lineageClassList = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
import ai.timefold.solver.core.impl.testdata.domain.TestdataValue;
import ai.timefold.solver.core.impl.testdata.domain.extended.TestdataAnnotatedExtendedEntity;
import ai.timefold.solver.core.impl.testdata.domain.extended.TestdataAnnotatedExtendedSolution;
import ai.timefold.solver.core.impl.testdata.domain.interface_domain.TestdataInterfaceConstraintProvider;
import ai.timefold.solver.core.impl.testdata.domain.interface_domain.TestdataInterfaceEntity;
import ai.timefold.solver.core.impl.testdata.domain.interface_domain.TestdataInterfaceSolution;
import ai.timefold.solver.core.impl.testdata.domain.record.TestdataRecordEntity;
import ai.timefold.solver.core.impl.testdata.domain.record.TestdataRecordSolution;

Expand Down Expand Up @@ -226,6 +229,20 @@ void variableWithPlanningIdIsARecord() {
Assertions.assertThatNoException().isThrownBy(() -> solver.solve(solution));
}

@Test
void domainClassesAreInterfaces() {
var solverConfig = new SolverConfig()
.withSolutionClass(TestdataInterfaceSolution.class)
.withEntityClasses(TestdataInterfaceEntity.class)
.withConstraintProviderClass(TestdataInterfaceConstraintProvider.class)
.withPhases(new ConstructionHeuristicPhaseConfig()); // Run CH and finish.
var solver = SolverFactory.create(solverConfig)
.buildSolver();

var solution = TestdataInterfaceSolution.generateSolution();
Assertions.assertThatNoException().isThrownBy(() -> solver.solve(solution));
}

@Test
void entityWithTwoPlanningListVariables() {
var solverConfig = new SolverConfig()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package ai.timefold.solver.core.impl.testdata.domain.interface_domain;

import ai.timefold.solver.core.api.score.buildin.simple.SimpleScore;
import ai.timefold.solver.core.api.score.stream.Constraint;
import ai.timefold.solver.core.api.score.stream.ConstraintFactory;
import ai.timefold.solver.core.api.score.stream.ConstraintProvider;

public class TestdataInterfaceConstraintProvider implements ConstraintProvider {

@Override
public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
return new Constraint[] { alwaysPenalizingConstraint(constraintFactory) };
}

private Constraint alwaysPenalizingConstraint(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(TestdataInterfaceEntity.class)
.penalize(SimpleScore.ONE)
.asConstraint("Always penalize");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package ai.timefold.solver.core.impl.testdata.domain.interface_domain;

import ai.timefold.solver.core.api.domain.entity.PlanningEntity;
import ai.timefold.solver.core.api.domain.variable.PlanningVariable;

@PlanningEntity
public interface TestdataInterfaceEntity {
@PlanningVariable
TestdataInterfaceValue getValue();

void setValue(TestdataInterfaceValue value);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package ai.timefold.solver.core.impl.testdata.domain.interface_domain;

import java.util.List;

import ai.timefold.solver.core.api.domain.solution.PlanningEntityCollectionProperty;
import ai.timefold.solver.core.api.domain.solution.PlanningScore;
import ai.timefold.solver.core.api.domain.solution.PlanningSolution;
import ai.timefold.solver.core.api.domain.valuerange.ValueRangeProvider;
import ai.timefold.solver.core.api.score.buildin.simple.SimpleScore;
import ai.timefold.solver.core.impl.domain.solution.descriptor.SolutionDescriptor;

@PlanningSolution
public interface TestdataInterfaceSolution {
static SolutionDescriptor<TestdataInterfaceSolution> buildSolutionDescriptor() {
return SolutionDescriptor.buildSolutionDescriptor(TestdataInterfaceSolution.class, TestdataInterfaceEntity.class);
}

static TestdataInterfaceSolution generateSolution() {
var out = new TestdataInterfaceSolution() {
private List<TestdataInterfaceEntity> entityList;
private List<TestdataInterfaceValue> valueList;
private SimpleScore score;

@Override
public List<TestdataInterfaceEntity> getEntityList() {
return entityList;
}

@Override
public void setEntityList(List<TestdataInterfaceEntity> entityList) {
this.entityList = entityList;
}

@Override
public List<TestdataInterfaceValue> getValueList() {
return valueList;
}

@Override
public void setValueList(List<TestdataInterfaceValue> valueList) {
this.valueList = valueList;
}

@Override
public SimpleScore getScore() {
return score;
}

@Override
public void setScore(SimpleScore score) {
this.score = score;
}
};

out.setEntityList(List.of(
new TestdataInterfaceEntity() {
private TestdataInterfaceValue value;

@Override
public TestdataInterfaceValue getValue() {
return value;
}

@Override
public void setValue(TestdataInterfaceValue value) {
this.value = value;
}
}));

out.setValueList(List.of(
new TestdataInterfaceValue() {
}));

return out;
}

@PlanningEntityCollectionProperty
List<TestdataInterfaceEntity> getEntityList();

void setEntityList(List<TestdataInterfaceEntity> entityList);

@ValueRangeProvider
List<TestdataInterfaceValue> getValueList();

void setValueList(List<TestdataInterfaceValue> valueList);

@PlanningScore
SimpleScore getScore();

void setScore(SimpleScore score);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package ai.timefold.solver.core.impl.testdata.domain.interface_domain;

public interface TestdataInterfaceValue {
}
Loading