Skip to content

Commit c4e2538

Browse files
chore: remove autodiscover member type (#2133)
Co-authored-by: Lukáš Petrovický <lukas@petrovicky.net>
1 parent 3a5cb11 commit c4e2538

File tree

18 files changed

+9
-1057
lines changed

18 files changed

+9
-1057
lines changed

core/src/main/java/ai/timefold/solver/core/api/domain/autodiscover/AutoDiscoverMemberType.java

Lines changed: 0 additions & 32 deletions
This file was deleted.

core/src/main/java/ai/timefold/solver/core/api/domain/solution/PlanningSolution.java

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,9 @@
66
import java.lang.annotation.Retention;
77
import java.lang.annotation.Target;
88

9-
import ai.timefold.solver.core.api.domain.autodiscover.AutoDiscoverMemberType;
109
import ai.timefold.solver.core.api.domain.solution.cloner.SolutionCloner;
1110
import ai.timefold.solver.core.api.score.stream.ConstraintProvider;
1211

13-
import org.jspecify.annotations.NonNull;
14-
1512
/**
1613
* Specifies that the class is a planning solution.
1714
* A solution represents a problem and a possible solution of that problem.
@@ -42,21 +39,6 @@
4239
@Target({ TYPE })
4340
@Retention(RUNTIME)
4441
public @interface PlanningSolution {
45-
46-
/**
47-
* Enable reflection through the members of the class
48-
* to automatically assume {@link PlanningScore}, {@link PlanningEntityCollectionProperty},
49-
* {@link PlanningEntityProperty}, {@link ProblemFactCollectionProperty}, {@link ProblemFactProperty}
50-
* and {@link ConstraintWeightOverrides} annotations based on the member type.
51-
*
52-
* <p>
53-
* This feature is not supported under Quarkus.
54-
* When using Quarkus,
55-
* setting this to anything other than {@link AutoDiscoverMemberType#NONE} will result in a build-time exception.
56-
*/
57-
@NonNull
58-
AutoDiscoverMemberType autoDiscoverMemberType() default AutoDiscoverMemberType.NONE;
59-
6042
/**
6143
* Overrides the default {@link SolutionCloner} to implement a custom {@link PlanningSolution} cloning implementation.
6244
* <p>

core/src/main/java/ai/timefold/solver/core/impl/domain/solution/descriptor/SolutionDescriptor.java

Lines changed: 8 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import java.lang.reflect.Field;
1111
import java.lang.reflect.Member;
1212
import java.lang.reflect.Method;
13-
import java.lang.reflect.ParameterizedType;
1413
import java.util.ArrayList;
1514
import java.util.Arrays;
1615
import java.util.Collection;
@@ -34,7 +33,6 @@
3433
import java.util.stream.Collectors;
3534
import java.util.stream.Stream;
3635

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

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

261259
private DomainAccessType domainAccessType;
262-
private AutoDiscoverMemberType autoDiscoverMemberType;
263260
private LookUpStrategyResolver lookUpStrategyResolver;
264261

265262
private final Map<String, MemberAccessor> problemFactMemberAccessorMap = new LinkedHashMap<>();
@@ -337,7 +334,7 @@ private void processConstraintWeights(DescriptorPolicy descriptorPolicy) {
337334
}
338335
}
339336

340-
public void processAnnotations(DescriptorPolicy descriptorPolicy, List<Class<?>> entityClassList) {
337+
public void processAnnotations(DescriptorPolicy descriptorPolicy) {
341338
domainAccessType = descriptorPolicy.getDomainAccessType();
342339
processSolutionAnnotations(descriptorPolicy);
343340
var potentiallyOverwritingMethodList = new ArrayList<Method>();
@@ -356,7 +353,7 @@ public void processAnnotations(DescriptorPolicy descriptorPolicy, List<Class<?>>
356353
continue;
357354
}
358355
processValueRangeProviderAnnotation(descriptorPolicy, member);
359-
processFactEntityOrScoreAnnotation(descriptorPolicy, member, entityClassList);
356+
processFactEntityOrScoreAnnotation(descriptorPolicy, member);
360357
}
361358
potentiallyOverwritingMethodList.ensureCapacity(potentiallyOverwritingMethodList.size() + memberList.size());
362359
memberList.stream().filter(Method.class::isInstance)
@@ -382,7 +379,6 @@ Maybe add a getScore() method with a @%s annotation."""
382379

383380
private void processSolutionAnnotations(DescriptorPolicy descriptorPolicy) {
384381
var annotation = extractMostRelevantPlanningSolutionAnnotation();
385-
autoDiscoverMemberType = annotation.autoDiscoverMemberType();
386382
var solutionClonerClass = annotation.solutionCloner();
387383
if (solutionClonerClass != PlanningSolution.NullSolutionCloner.class) {
388384
solutionCloner = ConfigUtils.newInstance(this::toString, "solutionClonerClass", solutionClonerClass);
@@ -422,9 +418,9 @@ private void processValueRangeProviderAnnotation(DescriptorPolicy descriptorPoli
422418
}
423419

424420
private void processFactEntityOrScoreAnnotation(DescriptorPolicy descriptorPolicy,
425-
Member member, List<Class<?>> entityClassList) {
426-
var annotationClass = extractFactEntityOrScoreAnnotationClassOrAutoDiscover(
427-
member, entityClassList);
421+
Member member) {
422+
var annotationClass = extractFactEntityOrScoreAnnotationClass(
423+
member);
428424
if (annotationClass == null) {
429425
return;
430426
}
@@ -444,63 +440,12 @@ private void processFactEntityOrScoreAnnotation(DescriptorPolicy descriptorPolic
444440
}
445441
}
446442

447-
private Class<? extends Annotation> extractFactEntityOrScoreAnnotationClassOrAutoDiscover(
448-
Member member, List<Class<?>> entityClassList) {
449-
var annotationClass = ConfigUtils.extractAnnotationClass(member,
443+
private static Class<? extends Annotation> extractFactEntityOrScoreAnnotationClass(Member member) {
444+
return ConfigUtils.extractAnnotationClass(member,
450445
ProblemFactProperty.class,
451446
ProblemFactCollectionProperty.class,
452447
PlanningEntityProperty.class, PlanningEntityCollectionProperty.class,
453448
PlanningScore.class);
454-
if (annotationClass == null) {
455-
Class<?> type;
456-
if (autoDiscoverMemberType == AutoDiscoverMemberType.FIELD
457-
&& member instanceof Field field) {
458-
type = field.getType();
459-
} else if (autoDiscoverMemberType == AutoDiscoverMemberType.GETTER
460-
&& (member instanceof Method method) && ReflectionHelper.isGetterMethod(method)) {
461-
type = method.getReturnType();
462-
} else {
463-
type = null;
464-
}
465-
if (type != null) {
466-
if (Score.class.isAssignableFrom(type)) {
467-
annotationClass = PlanningScore.class;
468-
} else if (Collection.class.isAssignableFrom(type) || type.isArray()) {
469-
Class<?> elementType;
470-
if (Collection.class.isAssignableFrom(type)) {
471-
var genericType = (member instanceof Field f) ? f.getGenericType()
472-
: ((Method) member).getGenericReturnType();
473-
var memberName = member.getName();
474-
if (!(genericType instanceof ParameterizedType)) {
475-
throw new IllegalArgumentException(
476-
"""
477-
The solutionClass (%s) has a auto discovered member (%s) with a member type (%s) that returns a %s which has no generic parameters.
478-
Maybe the member (%s) should return a typed %s."""
479-
.formatted(solutionClass, memberName, type, Collection.class.getSimpleName(),
480-
memberName, Collection.class.getSimpleName()));
481-
}
482-
elementType = ConfigUtils.extractGenericTypeParameter("solutionClass", solutionClass, type, genericType,
483-
null, member.getName()).orElse(Object.class);
484-
} else {
485-
elementType = type.getComponentType();
486-
}
487-
if (entityClassList.stream().anyMatch(entityClass -> entityClass.isAssignableFrom(elementType))) {
488-
annotationClass = PlanningEntityCollectionProperty.class;
489-
} else {
490-
annotationClass = ProblemFactCollectionProperty.class;
491-
}
492-
} else if (Map.class.isAssignableFrom(type)) {
493-
throw new IllegalStateException(
494-
"The autoDiscoverMemberType (%s) does not yet support the member (%s) of type (%s) which is an implementation of %s."
495-
.formatted(autoDiscoverMemberType, member, type, Map.class.getSimpleName()));
496-
} else if (entityClassList.stream().anyMatch(entityClass -> entityClass.isAssignableFrom(type))) {
497-
annotationClass = PlanningEntityProperty.class;
498-
} else {
499-
annotationClass = ProblemFactProperty.class;
500-
}
501-
}
502-
}
503-
return annotationClass;
504449
}
505450

506451
private void processProblemFactPropertyAnnotation(DescriptorPolicy descriptorPolicy, Member member,

0 commit comments

Comments
 (0)