18.2. Planning Values and Value Ranges

18.2.1. ValueRangeProvider

If you have a @ValueRangeProvider that returns a collection of numbers (for example List<Integer> or List<BigDecimal>), then you should switch to a ValueRange, which uses less memory and offers additional opportunities.
For example:
@ValueRangeProvider(id = "delayRange")
    public List<Integer> getDelayRange() {
        List<Integer> = new ArrayList<Integer>(5000);
        for (int i = 0; i < 5000; i++) {
            delayRange.add(i);
        }
        return delayRange;
    }
Is changed to:
@ValueRangeProvider(id = "delayRange")
    public CountableValueRange<Integer> getDelayRange() {
        return ValueRangeFactory.createIntValueRange(0, 5000);
    }
Note
The annotation @ValueRangeProvider has been moved into another package, from:
import org.optaplanner.core.api.domain.value.ValueRangeProvider;
to
import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;

18.2.2. Planning Variables

The interface PlanningVariableListener has been renamed to VariableListener.
Previously in *.java:
public class VehicleUpdatingVariableListener implements PlanningVariableListener<Customer> {
Now in *.java:
public class VehicleUpdatingVariableListener implements VariableListener<Customer> {
The class AbstractPlanningVariableListener has been removed.
Previously in *.java:
public class VehicleUpdatingVariableListener extends AbstractPlanningVariableListener<Customer> {
Now in *.java:
public class VehicleUpdatingVariableListener implements VariableListener<Customer> {
The VariableListener is now declared on the shadow side, instead of the @PlanningVariable side. This way, Business Rules Planner recognizes the shadow variables, and all shadow variables are declared in a consistent matter. Furthermore, it allows a shadow variable to based on other shadow variable.
Previously in *.java:
@PlanningVariable(valueRangeProviderRefs = {"vehicleRange", "customerRange"},
graphType = PlanningVariableGraphType.CHAINED,
variableListenerClasses = {VehicleUpdatingVariableListener.class, ArrivalTimeUpdatingVariableListener.class})
public Standstill getPreviousStandstill() {
return previousStandstill;
}

public Vehicle getVehicle() {
return vehicle;
}

public Integer getArrivalTime() {
return arrivalTime;
}
Now in *.java:
@PlanningVariable(...)
public Standstill getPreviousStandstill() {
return previousStandstill;
}

@CustomShadowVariable(variableListenerClass = VehicleUpdatingVariableListener.class,
sources = {@CustomShadowVariable.Source(variableName = "previousStandstill")})
public Vehicle getVehicle() {
	return vehicle;
}

@CustomShadowVariable(variableListenerClass = ArrivalTimeUpdatingVariableListener.class,
sources = {@CustomShadowVariable.Source(variableName = "previousStandstill")})
public Integer getArrivalTime() {
	return arrivalTime;
}

There is now out-of-the-box support for a shadow variable representing the anchor of a chained variable. For example, in a VRP each Customer (= entity) needs to know to which Vehicle (= anchor) it belongs. This declarative support allows build-in selectors to reuse that knowledge without duplicating the calculation.
Previously in *.java:
@PlanningEntity
public class Customer implements Standstill {

	@PlanningVariable(...)
	public Standstill getPreviousStandstill() {...}

	@CustomShadowVariable(variableListenerClass = VehicleUpdatingVariableListener.class,
		sources = {@CustomShadowVariable.Source(variableName = "previousStandstill")})
		public Vehicle getVehicle() {...}

}
public class VehicleUpdatingVariableListener implements VariableListener<Customer> {
...
}
Now in *.java:
@PlanningEntity
public class Customer implements Standstill {

	@PlanningVariable(...)
	public Standstill getPreviousStandstill() {...}

	@AnchorShadowVariable(sourceVariableName = "previousStandstill")
	public Vehicle getVehicle() {...}
}
To scale VRP cases, Nearby Selection is critical. It is now finally completely supported and documented.