I have a class with an overloaded function, and was expecting Java to use the most specific implementation based on runtime type. However, it is always invoking the more generically-defined method in the below situation. Why is this?
I added comments in the code where the action is happening.
/** The entity class inheritance */
public abstract class AbstractHistory { }
public class IndicatorHistory extends AbstractHistory { }
/** The config class inheritance */
public class SynchResourceConfig { }
public class SynchIndicatorSenderConfig extends SynchResourceConfig { }
/** Class with overloaded methods */ 
public class ConfigFilter {
    public boolean shouldProcess(AbstractHistory history, SynchResourceConfig config) {
        logger.info("Using basic filter config");
        return config.isEnabled();
    }
    public boolean shouldProcess(IndicatorHistory history, SynchIndicatorSenderConfig sender) {
        logger.info("Using the Indicator sender config");
        return true;
    }
}
/** Use of the actual method */
private void updateCatalogWithHistoryData(MyType type, SynchResourceSettings senderSettings, long lastId) {
        HistoryDao historyDao = daoService.lookup(type);
        SynchResourceConfig savedConfig = senderSettings.getResources().get(type);
        // The below line always invokes the less specific method
        // (AbstractHistory history, SynchResourceConfig config)
        // even tho, when debugged, it definitely passes objects with runtime values of
        // (IndicatorHistory history, SynchIndicatorSenderConfig sender)
        Predicate<AbstractHistory> filter = (history) -> configFilter.shouldProcess(history, savedConfig);
        historyDao.findById(lastId).filter(filter).forEach(sendRecord(type)));
    }
}
 
    