Search code examples
javacollectionsguava

Guava ClassToInstanceMap for generic types


I need to maintain a java map like Map<Class<? extends T>, Repository<T>> and retrieve the repository instance without casting.

The closest implementation I could find is Guava's ClassToInstanceMap. But it seems to support only Map<Class<? extends T>, T>

Is it possible to use ClassToInstanceMap to represent Map<Class<? extends T>, Repository<T>>, or is there a better way to implement this?

Here is an example showing the cast error at repositories.get(entityClass).save(entity);

// Entity types

interface Entity {
}

class Entity1 implements Entity {
}

class Entity2 implements Entity {
}

// Repositories

interface Repository<T extends Entity> {
    default void save(T entity) {};
}

class Entity1Repository implements Repository<Entity1> {
}

class Entity2Repository implements Repository<Entity2> {
}

public class Processor {

    private static Map<Class<? extends Entity>, Repository<? extends Entity>> repositories = new HashMap<>();

    public static void main(String[] args) {

        // Initialize map
        repositories.put(Entity1.class, new Entity1Repository());
        repositories.put(Entity2.class, new Entity2Repository());
    }

    public static void save(Class<? extends Entity> entityClass, Entity entity) {
        repositories.get(entityClass).save(entity); // Cast error
    }
}

Solution

  • No, it's not possible to use ClassToInstanceMap. Your sample code uses the correct approach; you will have to use an unsafe map and do the unsafe cast.