sinuhepop
sinuhepop

Reputation: 20307

Redundant generic parameters

I have this two interfaces and classes:

public interface Identifiable<T> {
    T getId();
}

public interface GenericRepository<T extends Identifiable<K>, K> {
    T get(K id);
}

public class MyEntity implements Identifiable<Long> {

    private Long id;

    public Long getId() {
        return id;
    }
}

public class MyService {
    private GenericRepository<MyEntity, Long> myEntityRepository;
}

It all works as desired. But in my opinion second generic parameter in GenericRepository (K) is redundant. Because I know that MyEntity is an Identifiable, I think it would be great if I can finally use it like this:

public class MyService {
    private GenericRepository<MyEntity> myEntityRepository;
}

But I'm trying different things without succeeding. Is it possible? If not, why not?

UPDATE: Answering some responses. I think compiler knows something about which type is the generic in MyEntity. For example:

public class MyEntityGenericRepository implements GenericRepository<MyEntity, Long> {
    // compiles...
}

public class MyEntityGenericRepository implements GenericRepository<MyEntity, String> {
    // compiler says: "Bound mismatch: The type MyEntity is not a valid substitute for the bounded parameter <T extends Identifiable<K>> of the type GenericRepository<T,K>"
}

Upvotes: 9

Views: 752

Answers (6)

P&#233;ter T&#246;r&#246;k
P&#233;ter T&#246;r&#246;k

Reputation: 116266

I don't think you can omit it. With T extends Identifiable<K> you want to say that the generic type parameter must be an Identifiable. Since Identifiable is a generic class, you need to mention its generic type parameter too (if you want to play by the rules that is - if you omit it, you lose all generic type safety for GenericRepository, due to backward compatibility rules). Note also that K is actually used as the parameter type of GenericRepository.get. And since that type may be different from T, you need to satisfy the compiler by declaring it as another generic type parameter of GenericRepository. Otherwise the compiler has no way of knowing what K is.

Upvotes: 7

artbristol
artbristol

Reputation: 32407

Not much you can do, other than introduce an interface that just refines GenericRepository

  public interface LongKeyedRepository<T extends Identifiable<Long>> 
        extends GenericRepository<T, Long> { {
  //No new methods need to be defined
  }

Then you can have

private LongKeyedRepository<MyEntity> myEntityRepository;

etc.

Upvotes: 1

aretai
aretai

Reputation: 1641

It would work with (i.e. compile)

public interface GenericRepository<T extends Identifiable> {
    T get(T id);
}

but it says nonetheless that Identifiable is a raw type and that it should be parametrized.

Hope it helps.

Upvotes: 0

Rahul Borkar
Rahul Borkar

Reputation: 2762

Why you cannot remove second K from,

public interface GenericRepository<T extends Identifiable<K>, K> {

So rather than having it as above, can we have it as

public interface GenericRepository<T extends Identifiable<K>> {

By this we can do what you want to do.

Upvotes: -1

UmNyobe
UmNyobe

Reputation: 22890

If I am not mistaken generics will all be compiled as if they were just Object. Now the syntax is (hard) checked to ensure that you are not putting apple with oranges because generics were added after the initial design of Java. this is why generics are so constrained...

Upvotes: 0

Malcolm
Malcolm

Reputation: 41510

It's not redundant from the standpoint of the GenericRepository class. When it has methods like T get(K id), it can't know which types of the id argument it can accept otherwise. You can write the following:

interface GenericRepository<T extends Identifiable<?>> {
    T get(Object id);
}

Now you don't have to write Long as a type parameter, but you lose the possibility to check if the get method is used properly at compile time. So the type variable serves a specific purpose.

And as for the field declaration, when you have a generic type, you have to specify all the type variables it uses. Of course, you could argue that it would be neat if the language could understand that one of the parameter values can be inferred from the other one, but it is debatable.

Upvotes: 3

Related Questions