1

Consider the following code:

public abstract class MyObject {
}

public interface Dao<T extends MyObject> {
}

public abstract class JsonDao<T extends MyObject> implements Dao<T> {
}

public abstract class SqliteDao<T extends MyObject> implements Dao<T> {
}

public interface DaoFactory<*????*> {
    public *????* getDao(Class<? extends MyObject> objectClass);
}

Now what I'd like is for getDao to be able to instanciate both JsonDao and SqliteDao, but parametrized with a class extending MyObject, basically something like this:

public interface DaoFactory<T<? extends MyObject> extends Dao<? extends MyObject>> {
    public <U extends MyObject> T<U> getDao(Class<U> objectClass);
}

Is something similar even possible or does type erasure prevent it?

3
  • 1
    This isn't really an issue with type erasure. Java just doesn't have a feature for a syntactical construct like T<U>. Commented Jun 9, 2017 at 15:50
  • interface DaoFactory<U extends MyObject, T extends Dao<U>> ? Commented Jun 9, 2017 at 15:57
  • @Jorn Vernee I can't because the factory should instanciate Daos for multiple classes extending MyObject. Commented Jun 9, 2017 at 15:58

2 Answers 2

1

You could declare DaoFactory as follows:

public interface DaoFactory<D extends Dao<? extends MyObject>> {

    <T extends MyObject> D getDao(Class<T> type);
}

Then, JsonDaoFactory could be implemented as follows:

public class JsonDaoFactory implements DaoFactory<JsonDao<? extends MyObject>> {

    private final Map<Class<? extends MyObject>, JsonDao<? extends MyObject>> daos =
            new HashMap<>();

    public JsonDaoFactory() {
        daos.put(Contact.class, new JsonContactDao());
        daos.put(Customer.class, new JsonCustomerDao());
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T extends MyObject> JsonDao<T> getDao(Class<T> type) {
        return (JsonDao<T>) daos.get(type);
    }
}

I've used a Map to make every descendant of MyObject match its corresponding JsonDao (here I've used Contact and Customer, and JsonContactDao and JsonCustomerDao, respectively). I've suppressed an unchecked cast warning because I'm explicitly filling the map in the constructor, so I'm sure there won't be a ClassCastException.

For completeness, here's the code for SqliteDaoFactory:

public class SqliteDaoFactory implements DaoFactory<SqliteDao<? extends MyObject>> {

    private final Map<Class<? extends MyObject>, SqliteDao<? extends MyObject>> daos =
            new HashMap<>();

    public SqliteDaoFactory() {
        daos.put(Contact.class, new SqliteContactDao());
        daos.put(Customer.class, new SqliteCustomerDao());
    }

    @Override
    @SuppressWarnings("unchecked")
    public <T extends MyObject> SqliteDao<T> getDao(Class<T> type) {
        return (SqliteDao<T>) daos.get(type);
    }
}

The code for both factories is almost duplicated, but I couldn't find a way to solve this.

Here's how to use these factories:

JsonDaoFactory jsonDaoFactory = new JsonDaoFactory();
JsonDao<Contact> contactJsonDao = jsonDaoFactory.getDao(Contact.class);
JsonDao<Customer> customerJsonDao = jsonDaoFactory.getDao(Customer.class);

SqliteDaoFactory sqliteDaoFactory = new SqliteDaoFactory();
SqliteDao<Contact> contactSqliteDao = sqliteDaoFactory.getDao(Contact.class);
SqliteDao<Customer> customerSqliteDao = sqliteDaoFactory.getDao(Customer.class);
Sign up to request clarification or add additional context in comments.

7 Comments

Yeah but I posted only a fragment of my class hierarchy, I use the genericity further down in the concrete classes implementing DaoFactory.
Yes I think you're on to something like @Aarjav below, I'll try that tomorrow and I will let you know :)
Okay your code works, but I'm still stuck at instanciation: I have multiple concrete implementations of JsonDao, ie.: JsonContactDao (Contact extends MyObject, JsonContactDao extends JsonDao<Contact>). I can't find a way to instantiate a JsonContactDao in getDao.
Same functions with differents parameters (file name for json, different fields to load in Contact and Customer). The problem is I'm trying to "inherit" both the storage type (Json, Sqlite, etc.) and the entity (Contact/Customer) and at some point I can't reconcile the two.
That's very nice of you. If you vanna see the whole mess my code is here: bitbucket.org/GaetanL/glace/src, in glace/app/src/main/java/com/gaetanl/gl/persistence/ for the abstract/sdk part and glace/app/src/main/java/com/gaetanl/glace/persistence/ for the concrete implementation.
|
1

Does this fit your needs?

public interface DaoFactory<O extends MyObject, D extends Dao<O>> extends Dao<O> {
    public D getDao(Class<O> objectClass);
    //or for any subclass
    public <RO extends O, RD extends D<RO>> RD getSubDao(Class<RO> objectSubclass);

    //or maybe this
    public <RO extends O> Dao<RO> getSimpleSubDao(Class<RO> objectSubclass);
}

1 Comment

Sounds promising! I will test this tommorow I'll let you know!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.