I am trying to refactor some code, moving common code shared among a few caches to a base class. Here's a simplified concept of it:
public abstract class DBObject {
public void copyTo(DBObject other) {
other.setId(this.id);
}
}
public class Person extends DBObject {
public void copyTo(Person other) {
super.copyTo(other);
other.setName(this.name);
}
}
public class PersonCache extends Cache<Person> {
}
public abstract class Cache<T extends DBObject> {
Map<Long, T> idToCachedMap;
private Class<T> tObjectClass;
public void initialize() {
// does stuff to populate the idToCachedMap
}
public void updateCache(T cachedObjToUpdate) {
T cachedObj = idToCachedMap.get(cachedObjToUpdate.getId());
T oldCachedObj = tObjectClass.newInstance();;
cachedObj.copyTo(oldCachedObj); // PROBLEM HERE
// do other stuff...
}
}
The problem I'm running into is that when I call updateCache(Person) on a PersonCache, the copyTo methods that get invoked on the objects are that in DBObject, as opposed to the one in Person. As a result, only some of the data is actually copied (in this example case, the ID, but not the name).
It seems to me that since both cachedObj and oldCachedObjs are guaranteed to be Person objects if it's a PersonCache, the copyTo method that should be called is the one on the Person class.
I feel like there must be something about how generics work that I'm missing that is causing this behavior. I know if I override copyTo in the Person class to be a signature of copyTo(DBObject other) rather than copyTo(Person other) it then does call the copyTo on the person class - but that'd be a sloppy way to rewrite it and I think I'm missing something that might be cleaner.