Skip to content
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

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import ai.timefold.solver.core.api.domain.autodiscover.AutoDiscoverMemberType;
import ai.timefold.solver.core.api.domain.solution.cloner.SolutionCloner;
import ai.timefold.solver.core.api.score.stream.ConstraintProvider;

import org.jspecify.annotations.NonNull;

/**
* Specifies that the class is a planning solution.
* A solution represents a problem and a possible solution of that problem.
Expand Down Expand Up @@ -42,21 +39,6 @@
@Target({ TYPE })
@Retention(RUNTIME)
public @interface PlanningSolution {

/**
* Enable reflection through the members of the class
* to automatically assume {@link PlanningScore}, {@link PlanningEntityCollectionProperty},
* {@link PlanningEntityProperty}, {@link ProblemFactCollectionProperty}, {@link ProblemFactProperty}
* and {@link ConstraintWeightOverrides} annotations based on the member type.
*
* <p>
* This feature is not supported under Quarkus.
* When using Quarkus,
* setting this to anything other than {@link AutoDiscoverMemberType#NONE} will result in a build-time exception.
*/
@NonNull
AutoDiscoverMemberType autoDiscoverMemberType() default AutoDiscoverMemberType.NONE;

/**
* Overrides the default {@link SolutionCloner} to implement a custom {@link PlanningSolution} cloning implementation.
* <p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
Expand All @@ -34,7 +33,6 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import ai.timefold.solver.core.api.domain.autodiscover.AutoDiscoverMemberType;
import ai.timefold.solver.core.api.domain.entity.PlanningEntity;
import ai.timefold.solver.core.api.domain.solution.ConstraintWeightOverrides;
import ai.timefold.solver.core.api.domain.solution.PlanningEntityCollectionProperty;
Expand Down Expand Up @@ -139,7 +137,7 @@ public static <Solution_> SolutionDescriptor<Solution_> buildSolutionDescriptor(
descriptorPolicy.setMemberAccessorFactory(solutionDescriptor.getMemberAccessorFactory());

solutionDescriptor.processUnannotatedFieldsAndMethods(descriptorPolicy);
solutionDescriptor.processAnnotations(descriptorPolicy, entityClassList);
solutionDescriptor.processAnnotations(descriptorPolicy);
// Before iterating over the entity classes, we need to read the inheritance chain,
// add all parent and child classes, and sort them.
var updatedEntityClassList = new ArrayList<>(entityClassList);
Expand Down Expand Up @@ -259,7 +257,6 @@ private static boolean hasAnyAnnotatedMembers(Class<?> solutionClass) {
private final MemberAccessorFactory memberAccessorFactory;

private DomainAccessType domainAccessType;
private AutoDiscoverMemberType autoDiscoverMemberType;
private LookUpStrategyResolver lookUpStrategyResolver;

private final Map<String, MemberAccessor> problemFactMemberAccessorMap = new LinkedHashMap<>();
Expand Down Expand Up @@ -337,7 +334,7 @@ private void processConstraintWeights(DescriptorPolicy descriptorPolicy) {
}
}

public void processAnnotations(DescriptorPolicy descriptorPolicy, List<Class<?>> entityClassList) {
public void processAnnotations(DescriptorPolicy descriptorPolicy) {
domainAccessType = descriptorPolicy.getDomainAccessType();
processSolutionAnnotations(descriptorPolicy);
var potentiallyOverwritingMethodList = new ArrayList<Method>();
Expand All @@ -356,7 +353,7 @@ public void processAnnotations(DescriptorPolicy descriptorPolicy, List<Class<?>>
continue;
}
processValueRangeProviderAnnotation(descriptorPolicy, member);
processFactEntityOrScoreAnnotation(descriptorPolicy, member, entityClassList);
processFactEntityOrScoreAnnotation(descriptorPolicy, member);
}
potentiallyOverwritingMethodList.ensureCapacity(potentiallyOverwritingMethodList.size() + memberList.size());
memberList.stream().filter(Method.class::isInstance)
Expand All @@ -382,7 +379,6 @@ Maybe add a getScore() method with a @%s annotation."""

private void processSolutionAnnotations(DescriptorPolicy descriptorPolicy) {
var annotation = extractMostRelevantPlanningSolutionAnnotation();
autoDiscoverMemberType = annotation.autoDiscoverMemberType();
var solutionClonerClass = annotation.solutionCloner();
if (solutionClonerClass != PlanningSolution.NullSolutionCloner.class) {
solutionCloner = ConfigUtils.newInstance(this::toString, "solutionClonerClass", solutionClonerClass);
Expand Down Expand Up @@ -422,9 +418,9 @@ private void processValueRangeProviderAnnotation(DescriptorPolicy descriptorPoli
}

private void processFactEntityOrScoreAnnotation(DescriptorPolicy descriptorPolicy,
Member member, List<Class<?>> entityClassList) {
var annotationClass = extractFactEntityOrScoreAnnotationClassOrAutoDiscover(
member, entityClassList);
Member member) {
var annotationClass = extractFactEntityOrScoreAnnotationClass(
member);
if (annotationClass == null) {
return;
}
Expand All @@ -444,63 +440,12 @@ private void processFactEntityOrScoreAnnotation(DescriptorPolicy descriptorPolic
}
}

private Class<? extends Annotation> extractFactEntityOrScoreAnnotationClassOrAutoDiscover(
Member member, List<Class<?>> entityClassList) {
var annotationClass = ConfigUtils.extractAnnotationClass(member,
private static Class<? extends Annotation> extractFactEntityOrScoreAnnotationClass(Member member) {
return ConfigUtils.extractAnnotationClass(member,
ProblemFactProperty.class,
ProblemFactCollectionProperty.class,
PlanningEntityProperty.class, PlanningEntityCollectionProperty.class,
PlanningScore.class);
if (annotationClass == null) {
Class<?> type;
if (autoDiscoverMemberType == AutoDiscoverMemberType.FIELD
&& member instanceof Field field) {
type = field.getType();
} else if (autoDiscoverMemberType == AutoDiscoverMemberType.GETTER
&& (member instanceof Method method) && ReflectionHelper.isGetterMethod(method)) {
type = method.getReturnType();
} else {
type = null;
}
if (type != null) {
if (Score.class.isAssignableFrom(type)) {
annotationClass = PlanningScore.class;
} else if (Collection.class.isAssignableFrom(type) || type.isArray()) {
Class<?> elementType;
if (Collection.class.isAssignableFrom(type)) {
var genericType = (member instanceof Field f) ? f.getGenericType()
: ((Method) member).getGenericReturnType();
var memberName = member.getName();
if (!(genericType instanceof ParameterizedType)) {
throw new IllegalArgumentException(
"""
The solutionClass (%s) has a auto discovered member (%s) with a member type (%s) that returns a %s which has no generic parameters.
Maybe the member (%s) should return a typed %s."""
.formatted(solutionClass, memberName, type, Collection.class.getSimpleName(),
memberName, Collection.class.getSimpleName()));
}
elementType = ConfigUtils.extractGenericTypeParameter("solutionClass", solutionClass, type, genericType,
null, member.getName()).orElse(Object.class);
} else {
elementType = type.getComponentType();
}
if (entityClassList.stream().anyMatch(entityClass -> entityClass.isAssignableFrom(elementType))) {
annotationClass = PlanningEntityCollectionProperty.class;
} else {
annotationClass = ProblemFactCollectionProperty.class;
}
} else if (Map.class.isAssignableFrom(type)) {
throw new IllegalStateException(
"The autoDiscoverMemberType (%s) does not yet support the member (%s) of type (%s) which is an implementation of %s."
.formatted(autoDiscoverMemberType, member, type, Map.class.getSimpleName()));
} else if (entityClassList.stream().anyMatch(entityClass -> entityClass.isAssignableFrom(type))) {
annotationClass = PlanningEntityProperty.class;
} else {
annotationClass = ProblemFactProperty.class;
}
}
}
return annotationClass;
}

private void processProblemFactPropertyAnnotation(DescriptorPolicy descriptorPolicy, Member member,
Expand Down
Loading
Loading