1

I have the following class:

public abstract class BaseDaoImpl<T extends BaseEntity> implements BaseDao<T> {


    @Override
    public T createOrUpdate(T t, User user) {
        return createOrUpdate(t, true, user);
    }

    @Override
    public void addOnwerUserToEntity(String entityType, Long entityId, User user) {

        BaseEntity baseEntity = findBaseEntityById(entityType, entityId);

        baseEntity.addOwnerUser(user);

        createOrUpdate(baseEntity, user); // compilation error
    }

}

right now I have the following compilation error:

The method createOrUpdate(T, User) in the type BaseDaoImpl<T> is not applicable for the arguments (BaseEntity, User)    

What am I doing wrong, why createOrUpdate method doesn't accept BaseEntity object and how to fix it ?

alexanoid
  • 24,051
  • 54
  • 210
  • 410
  • 5
    Why would it accept a `BaseEntity` value? You've declared `createOrUpdate` to accept a `T`. – Sotirios Delimanolis Sep 07 '17 at 19:57
  • 2
    It's often easier to understand when you replace the classes by concrete examples. T = Banana. BaseEntity = Fruit. You define a method createOrUpdate(Banana), and you call it with an argument of type Fruit. A Fruit is not necessarily a Banana. So the compiler doesn't accept the method call. – JB Nizet Sep 07 '17 at 19:59
  • But T is declared to accept BaseEntity and subclasses. Right now I don't understand why it doesn't accept BaseEntity.. – alexanoid Sep 07 '17 at 20:00
  • 2
    We can't really know _how to fix it_ without knowing your use case (or what `findBaseEntityById` is). – Sotirios Delimanolis Sep 07 '17 at 20:01
  • 1
    List accepts any class as generis type. But you can't add a Fruit to a List. Because the Fruit could be an Apple, or a Lemon, i.e. another type than T. – JB Nizet Sep 07 '17 at 20:02
  • I got it, thanks ! – alexanoid Sep 07 '17 at 20:05
  • 1
    @alexanoid You may want to take a look at the [PECS mnemonic](https://stackoverflow.com/questions/2723397/what-is-pecs-producer-extends-consumer-super). – Turing85 Sep 07 '17 at 20:05

3 Answers3

2

The thing is, T is not necessarily a BaseEntity. You could instantiate class BaseDaoImpl like so:

class Widget extends BaseEntity {...}
BaseDaoImpl<Widget> base = new BaseDaoImpl<>();

In this case, T is a Widget, and so the method createOrUpdate(...) becomes:

public Widget createOrUpdate(Widget t, User user) {

and you cannot call that with just a BaseEntity.

Turing85
  • 18,217
  • 7
  • 33
  • 58
Jamie
  • 1,888
  • 1
  • 18
  • 21
1

Change

BaseEntity baseEntity = findBaseEntityById(entityType, entityId);

to

T baseEntity = findBaseEntityById(entityType, entityId);

I assume that BaseDao<T>.findBaseEntityById() has return type T. If not, it should! :-)

markusk
  • 6,477
  • 34
  • 39
0

You are hoping that your "T extends BaseEntity" covers BaseEntity and it could be passed anywhere where you put 'T' as parameter. Not such luck my friend. Please review your understanding of generics .

Felix
  • 1,662
  • 2
  • 18
  • 37