开发者

Extending generics in method parameter

I'm trying to extend a library that uses generics in entities and entities manager, so I have the following:

public class MyEntity extends ParentEntity extends BaseEntity

and

public class MyEntityManager extends ParentEntityManager extends BaseEntityManager<ParentEntity, ParentEntityDao>

Now my problem is, I'm using another class of the library to update the entity, and the method I need to call expects:

public <ENT extends BaseEntity> void update (Class<ENT> entityClass, BaseEntityManager<ENT> entityManager)

So when I try to call the method with MyEntity an开发者_Go百科d MyEntityManager, it fails because my EntityManager extends from the BaseEntityManager with ParentEntity as parameter, not MyEntity, so they don't match.

I would say that the cleanest way to solve this would be to copy the utility class that has the update method and extend it in my project, but I would like to make it generic so I can pass it EntityManagers that use any children class of ParentEntity, but I've been trying for a while and I cannot find the solution.

I tried changing the method signature to this:

public <ENT extends BaseEntity> void update (Class<ENT> entityClass, BaseEntityManager<? extends ENT> entityManager)

but I'm still getting a compiler exception...

EDIT: Modifying ParentEntityManager, BaseEntityManager or ParentEntity is not possible, since there are too many dependencies to those classes


Since it doesn't appear you can easily fix the problem I would use a work around. You can use type erasure.

update((Class) MyEntity.class, myEntityManager);

This will compile with a warning. The warning is valid IMHO as your class structure isn't entirely logical ;) You can suppress this warning if you want.


What I do is; the container class returns the type of object it contains/manages.

class BaseEntityManager<E> {
    private final Class<E> typeManaged;
    public Class<E> typeManaged() { return typeManaged; }
}

// remove duplicate class parameter
public <ENT extends BaseEntity> void update (BaseEntityManager<ENT> entityManager)

The manager know what type it manages and the update() method can ask it by calling typeManaged(). This avoid having to give a matching type or for this type to be checked.


The problem you have is that

MyEntityManager extends BaseEntityManager<ParentEntity>

Which mean the class you have to provide is ParentEntity.class not MyEntity.class.

It appears the real solution is that you need to change

MyEntityManager extends BaseEntityManager<MyEntity>

This would be more logical IMHO and fix your problem.


You need to call the update method with ParentEntity.class and a MyEntityManager, e.g.

update(ParentEntity.class, new MyEntityManager());

because your MyEntityManager is a BaseEntityManager<ParentEntity>.

If this is not what you want (because for example update creates new objects of entityClass and you want them to be MyEntity instances), you need to change the signature of the update method and introduce wildcards:

public <ENT extends BaseEntity> void update (Class<? extends ENT> entityClass, BaseEntityManager<ENT> entityManager)

Now you can call it with MyEntity.class and a MyEntityManager.


I think if you look replace the Manager with Container then the problem becomes apparent: MyEntityManager manages all sorts of super ParentEntity classes, while the update method wants one catering specifically to the subclass.

Does the following work for you? It compiles but lint complains

class BaseEntity {} 

class BaseEntityManager<ENT extends BaseEntity> {} 

class ParentEntity extends BaseEntity {}

class ParentEntityManager extends BaseEntityManager<ParentEntity> {} 

class MyEntityManager extends ParentEntityManager { public void update(ParentEntity e) {}} 

class MyEntity extends ParentEntity {}

class XEntityManager<ENT extends ParentEntity> extends BaseEntityManager<ENT>
{
    MyEntityManager _delegate;
    XEntityManager(MyEntityManager m)
    {
        _delegate = m;
    }

    public void update(ENT e)
    {
        _delegate.update(e);
    }
}



class Foo {
    public <ENT extends BaseEntity> void update (Class<ENT> entityClass, BaseEntityManager<ENT> entityManager) {} 

    void bar(MyEntity e, MyEntityManager m)
    {
        update(MyEntity.class, new XEntityManager(m));
    }

}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜