private PlanningValueRangeDescriptor buildValueRangeDescriptor(ValueRange valueRangeAnnotation) {
   switch (valueRangeAnnotation.type()) {
     case FROM_SOLUTION_PROPERTY:
       return new FromSolutionPropertyPlanningValueRangeDescriptor(this, valueRangeAnnotation);
     case FROM_PLANNING_ENTITY_PROPERTY:
       return new FromEntityPropertyPlanningValueRangeDescriptor(this, valueRangeAnnotation);
     case UNDEFINED:
       return new UndefinedPlanningValueRangeDescriptor(this, valueRangeAnnotation);
     default:
       throw new IllegalStateException(
           "The valueRangeType (" + valueRangeAnnotation.type() + ") is not implemented.");
   }
   // TODO Support plugging in other ValueRange implementations
 }
 private void validate(ValueRange valueRangeAnnotation) {
   if (!valueRangeAnnotation.solutionProperty().equals("")) {
     throw new IllegalArgumentException(
         "The planningEntityClass ("
             + variableDescriptor.getPlanningEntityDescriptor().getPlanningEntityClass()
             + ") has a PlanningVariable annotated property ("
             + variableDescriptor.getVariableName()
             + ") of type ("
             + valueRangeAnnotation.type()
             + ") with a non-empty solutionProperty ("
             + valueRangeAnnotation.solutionProperty()
             + ").");
   }
   if (valueRangeAnnotation.planningEntityProperty().equals("")) {
     throw new IllegalArgumentException(
         "The planningEntityClass ("
             + variableDescriptor.getPlanningEntityDescriptor().getPlanningEntityClass()
             + ") has a PlanningVariable annotated property ("
             + variableDescriptor.getVariableName()
             + ") of type ("
             + valueRangeAnnotation.type()
             + ") with an empty planningEntityProperty ("
             + valueRangeAnnotation.planningEntityProperty()
             + ").");
   }
 }
 private void processPlanningEntityProperty(ValueRange valueRangeAnnotation) {
   String planningEntityProperty = valueRangeAnnotation.planningEntityProperty();
   PlanningEntityDescriptor planningEntityDescriptor =
       variableDescriptor.getPlanningEntityDescriptor();
   rangePropertyAccessor =
       new ReflectionPropertyAccessor(
           planningEntityDescriptor.getPropertyDescriptor(planningEntityProperty));
   if (rangePropertyAccessor == null) {
     String exceptionMessage =
         "The planningEntityClass ("
             + planningEntityDescriptor.getPlanningEntityClass()
             + ") has a PlanningVariable annotated property ("
             + variableDescriptor.getVariableName()
             + ") that refers to a planningEntityProperty ("
             + planningEntityProperty
             + ") that does not exist.";
     if (planningEntityProperty.length() >= 2
         && Character.isUpperCase(planningEntityProperty.charAt(1))) {
       String correctedPlanningEntityProperty =
           planningEntityProperty.substring(0, 1).toUpperCase()
               + planningEntityProperty.substring(1);
       exceptionMessage +=
           " But it probably needs to be correctedPlanningEntityProperty ("
               + correctedPlanningEntityProperty
               + ") instead because the JavaBeans spec states"
               + " the first letter should be a upper case if the second is upper case.";
     }
     throw new IllegalArgumentException(exceptionMessage);
   }
   if (!Collection.class.isAssignableFrom(rangePropertyAccessor.getPropertyType())) {
     throw new IllegalArgumentException(
         "The planningEntityClass ("
             + planningEntityDescriptor.getPlanningEntityClass()
             + ") has a PlanningVariable annotated property ("
             + variableDescriptor.getVariableName()
             + ") that refers to a planningEntityProperty ("
             + planningEntityProperty
             + ") that does not return a Collection.");
   }
 }