public interface EntityId {
...
EntityId cloneWithNewId(long id);
}
public interface Ticket extends EntityId {
/// cloneWithNewId - is not mentioned in this interface
}
public record TicketImpl(...)
@Override
public Ticket cloneWithNewId(long id) {...}
The compiler gives the error, when I write in my unit test the line with "cloneWithNewId" call:
@Test
void shouldBookTicket() {
Ticket ticket = new TicketImpl(7L, 8L, Ticket.Category.PREMIUM, 21);
Ticket expectedTicket = ticket.cloneWithNewId(1L); // compiler error in this line
//...
}
"EntityId cannot be converted to Ticket. Required type: Ticket. Provided: EntityId"
Any ideas why? Seems to be not much different from classic examples for covariant return type.
It works if I make EnityId interface generic
public interface EntityId<? extends T> {
...
T cloneWithNewId(long id);
}
public interface Ticket extends EntityId<Ticket> {
/// cloneWithNewId - is not mentioned in this interface
}
It also works if I add the method declaration to Ticket interface:
public interface Ticket extends EntityId {
Ticket cloneWithNewId(long id);
}
But I do not understand, why it does not work when I override method from extended interface.
In the unit test, you are not invoking the method with the narrowed return type.
The compiler raises an error here, because the return type of Ticket#cloneWithNewId(long)
is EntityId
, as it is inherited from EntityId
. Note that, when confronted with a compiler error, it does not make sense to argue about a specific TicketImpl
instance, as you are not in a runtime. Instead only the declared type of each local variable is relevant.
This is also why
public interface Ticket {
@Override
public Ticket cloneWithNewId(long id);
}
will fix the compiler error.
Another possible fix is to change the unit test to
@Test
void shouldBookTicket() {
TicketImpl ticket = new TicketImpl(7L, 8L, Ticket.Category.PREMIUM, 21);
Ticket expectedTicket = ticket.cloneWithNewId(1L);
//...
}
as that will "point" the compiler to the method declaration in TicketImpl
, whose return type is narrowed to Ticket
.