I'm new to generics and delving into things that are basically well beyond the scope of my knowledge so please bear with me on this. Perhaps what I'm asking is silly but I cannot seem to find a definitive answer on whether or not what I wish to do is possible, perhaps because I don't know the correct terminology to look for.
I have two Java classes which are parameterized with an entity of type T - a repository and a service. Since all my repositories and all my services are going to be doing some identical basic tasks, my generic repo and service have implemented said tasks and made them available through protected functions to anything that extends them. So far, everything is peachy. Currently they look something like this:
Repository class:
public interface GenericRepo<T> {
protected T findObject();
}
Service class:
public class GenericService<T> {
private GenericRepo<T> repo;
public GenericService(GenericRepo<T> repo) {
this.repo = repo;
}
protected T findObject() {
return this.repo.findObject();
}
}
The problem comes when I wish to extend my service and allow people to use the subclass of the repository. While many of the entities are basic and the functionality is covered with the generic functions, sometimes a special case is needed to perform an additional function on an entity. In the setup, the repo is implemented/extended and then that extended class is passed to the service (which accepts it because it is a type of GenericRepo<T>
). The specific repo would look something like below:
public class ExtendedRepo implements GenericRepo<Entity> {
protected Entity findObjectByWeirdKeyOnEntity(String weirdKey) {
//awesome code that does stuff here
}
}
I've also declared the service as generic because there are lots of possibilities for custom functionality on the service as well. So, the GenericService
is also extended like below:
public class ExtendedService extends GenericService<Entity> {
public ExtendedService(ExtendedRepo repo) {
super(repo);
}
public Entity findObjectByWeirdKeyOnEntity() {
// Do stuff to generate weird key to search by
return this.repo.findObjectByWeirdKeyOnEntity(weirdKey);
}
}
This allows me to do custom functions on the service but also utilize all basic functions on the generic service without need to replicate code. However, because the variable repo
in GenericService
is declared as type GenericRepo<T>
, only those functions actually on type GenericRepo<T>
are available to the generic service class and/or anything that extends it. Therefore despite the fact I'm passing ExtendedRepo
to my ExtendedService
whose super class has created and made available an instance of the GenericRepo
class through the subclass of ExtendedRepo
, I cannot use the declared variable on GenericService
to call any of the functions on ExtendedRepo
. The code in the code block immediately above fails - this.repo
does not know about the function findObjectByWeirdKeyOnEntity
because it's a variable of type GenericRepo<T>
. Currently to use any custom function on the extended repository, I have done the following:
public class ExtendedService extends GenericService<Entity> {
private ExtendedRepo extendedRepo;
public ExtendedService(ExtendedRepo repo) {
super(repo);
this.extendedRepo = repo;
}
public Entity findObjectByWeirdKey() {
return this.extendedRepo.findObjectByWeirdKeyOnEntity(weirdKey);
}
}
Re-declaring and keeping a separate variable for the repository in the extended service seems wrong as I'm essentially keeping two instances of the same class just so I can use one custom function in the extended class while also using all common functionality of the super class. Is there any way to create the variable GenericRepo
on GenericService
to be of any type which extends GenericRepo
that will allow the classes extending GenericService
to use the custom methods on the extended version of the GenericRepo
class?