0

I am trying to use inheritence and generics to create my application, but it doesn't seem to work the way I expect it to. I'll show you what I mean (TL;DR at the bottom):

public interface IModel extends Serializable {
    public int save();
    public void update();
    public void delete();
}

// <T> is a JPA annotated entity/class
@SuppressWarnings("serial")
public abstract class Model<T> implements IModel {
    private final Repository<T> _repository;
    protected T _entity;

    public Model(T entity, Repository<T> repository) {
        this._entity = entity;
        this._repository = repository;
    }

    public int save() {
        return _repository.save(_entity);
    }
    ...
}

This is implemented in for example my AccountModel, which is a Model with generic Account (which is a JPA entity) and which implements IAccount.

public class AccountModel extends Model<Account> implements IAccount {
    private static final AccountRepository REPOSITORY = new AccountRepository();

    public AccountModel(Account entity) {
        super(entity, REPOSITORY);
    }
    // Method implementations...
}

My generic Repository looks like this:

public abstract class Repository<T> implements Serializable {

    private static SessionFactory SESSION_FACTORY;
    private final Class<T> _repositoryClass;
    private static boolean _initiated = false;

    public Repository(Class<T> repositoryClass) {

        if (!Repository._initiated) 
            setup();

        this._repositoryClass = repositoryClass;
    }

    private void setup() {
        // logics
        Repository._initiated = true;
    }

    public final Model<T> getById(int id) {

        Session session = SESSION_FACTORY.openSession();

        try {
            session.beginTransaction();
            T t = session.get(_repositoryClass, id);
            return new Model<T>(t, this); // As suggested by @Vlad
        }
        finally {
            session.close();
        }
    }
}

The account implementation of this abstract Repository is:

public class AccountRepository extends Repository<Account> {

    public AccountRepository() {
        super(Account.class);
    }

    public Model<Account> getByEmail(String emailAddress) {...}
}

So far so good, this is all working as expected. But I cannot use a Model<T> as a TModel.

TL;DR

I would like use the following line of code:
AccountModel account = new AccountRepository().getById(1);
Since AccountModel inherits Model<Account> and new AccountRepository().getById() always returns Model<Account> I expect this to work, but it doesn't.

What am I missing?

ivospijker
  • 702
  • 1
  • 7
  • 22
  • not every `Model` is an `AccountModel`, What do you expect to happen where there is an `AnotherCustomAccountModel` inside this repository, which also inherits from `Model`? It would be valid in there, as it´s a `Model`, but it doesn´t represent an `AccountModel` – SomeJavaGuy Jan 04 '17 at 08:50
  • I know, but I don't see (yet) why that matters. The `AccountRepository` always returns a `Model`, never a `Model`. Does the compiler miss this and therefore not work? – ivospijker Jan 04 '17 at 08:52
  • 2
    Maybe I wrong, but you'are trying to return `T`, not `Model` in your `getById()` implementation. replacing `return t;` with `return new Model(t, this);` should works fine – Vlad Bochenin Jan 04 '17 at 08:55
  • 3
    `AccountModel` is a sub-class of `Model`. You can't assign a `Model` to an `AccountModel` variable. This doesn't work regardless of generics. – Eran Jan 04 '17 at 08:57
  • @Eran Do you know if I can use casting to solve this? – ivospijker Jan 04 '17 at 09:02
  • What prevents you from doing `Model account = new AccountRepository().getById(1)`? Why do you need an `AccountModel` specifically? – sisyphus Jan 04 '17 at 16:14

0 Answers0