in core/optaplanner-core-impl/src/main/java/org/optaplanner/core/impl/domain/solution/descriptor/SolutionDescriptor.java [310:383]
private Class<? extends Annotation> extractFactEntityOrScoreAnnotationClassOrAutoDiscover(
Member member, List<Class<?>> entityClassList) {
Class<? extends Annotation> annotationClass = ConfigUtils.extractAnnotationClass(member,
ConstraintConfigurationProvider.class,
ProblemFactProperty.class,
ProblemFactCollectionProperty.class,
PlanningEntityProperty.class, PlanningEntityCollectionProperty.class,
PlanningScore.class);
if (annotationClass == null) {
Class<?> type;
if (autoDiscoverMemberType == AutoDiscoverMemberType.FIELD
&& member instanceof Field) {
Field field = (Field) member;
type = field.getType();
} else if (autoDiscoverMemberType == AutoDiscoverMemberType.GETTER
&& (member instanceof Method) && ReflectionHelper.isGetterMethod((Method) member)) {
Method method = (Method) member;
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)) {
Type genericType = (member instanceof Field) ? ((Field) member).getGenericType()
: ((Method) member).getGenericReturnType();
String memberName = member.getName();
if (!(genericType instanceof ParameterizedType)) {
throw new IllegalArgumentException("The solutionClass (" + solutionClass + ") has a "
+ "auto discovered member (" + memberName + ") with a member type (" + type
+ ") that returns a " + Collection.class.getSimpleName()
+ " which has no generic parameters.\n"
+ "Maybe the member (" + memberName + ") should return a typed "
+ Collection.class.getSimpleName() + ".");
}
elementType = ConfigUtils.extractCollectionGenericTypeParameterLeniently(
"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 if (elementType.isAnnotationPresent(ConstraintConfiguration.class)) {
throw new IllegalStateException("The autoDiscoverMemberType (" + autoDiscoverMemberType
+ ") cannot accept a member (" + member
+ ") of type (" + type
+ ") with an elementType (" + elementType
+ ") that has a @" + ConstraintConfiguration.class.getSimpleName() + " annotation.\n"
+ "Maybe use a member of the type (" + elementType + ") directly instead of a "
+ Collection.class.getSimpleName() + " or array of that type.");
} else {
annotationClass = ProblemFactCollectionProperty.class;
}
} else if (Map.class.isAssignableFrom(type)) {
throw new IllegalStateException("The autoDiscoverMemberType (" + autoDiscoverMemberType
+ ") does not yet support the member (" + member
+ ") of type (" + type
+ ") which is an implementation of " + Map.class.getSimpleName() + ".");
} else if (entityClassList.stream().anyMatch(entityClass -> entityClass.isAssignableFrom(type))) {
annotationClass = PlanningEntityProperty.class;
} else if (type.isAnnotationPresent(ConstraintConfiguration.class)) {
annotationClass = ConstraintConfigurationProvider.class;
} else {
annotationClass = ProblemFactProperty.class;
}
}
}
return annotationClass;
}