Home > database >  Interfacing with generic types
Interfacing with generic types

Time:09-29

I am struggling to find and understand the error in the following code from my recent school project. I think that I can learn a lot from this mistake with your help !

I have this 'main' class in which I store a map of my different DAOs like so:

class Main {
   private static Map<Class<?>, Repository<?, ?>> daos = new HashMap<>();
   ...

   public void init() {
      daos.put(Account.class, new AccountDAO());

      List<Account> accounts = new ArrayList<Account>();
      ... using Faker to create new instances of the class Account ...

      daos.get(Account.class).saveAll(accounts);
   }
}

This last line produces an error message about casting and generic types:

The method saveAll(Iterable<S extends capture#of ?>) in the type Repository<capture#5-of ?,capture#6-of ?> is not applicable for the arguments (Iterable)

For the sake of learning by coding, I made my custom Repository class like so:

public interface Repository<T, K> {
    final static EntityManager ENTITY_MANAGER = EntityManagerHelper.getEntityManager();

    public default <S extends T> void save(S entity) {
        try {
            EntityManagerHelper.beginTransaction();
            ENTITY_MANAGER.persist(entity);
            EntityManagerHelper.commit();
        } catch (Exception exception) {
            System.err.println(exception.getMessage());
            EntityManagerHelper.rollback();
        }
    }

    public default <S extends T> void saveAll(Iterable<S> objects) {
        for (S object : objects) {
            this.save(object);
        }
    }


}

And for example, I have a class that implements the above code:

public class AccountDAO implements fr.istic.taa.jpa.repository.Repository<Account, String> {
...
}

CodePudding user response:

 public default <S extends T> void saveAll(Iterable<S> objects) {

means that generic type S should have type T or a subtype of type T. Practically in your example it means you expect an Iterable of generic type Account.

However when you try to get the repository class from the Dao map it's type is not known during compile time because it's declared as: Repository<?, ?>

Therefore you have to specify it in your code like:

Repository<Account, String> repository = (Repository<Account, String>) daos.get(Account.class);

repository.saveAll(accounts);
  • Related