3

So I have this bit of code:

public PacketListener packetListener;

@Override
protected void channelRead0(ChannelHandlerContext ctx, Packet<?> packet) throws Exception
{
    if (this.channel.isOpen()) {
        try {
            packet.handle(this.packetListener);
        }
        catch (Exception ex) {
            ;
        }
    }
}

on packet.handle(this.packetListener); I get the error: The method handle(capture#1-of ?) in the type Packet<capture#1-of ?> is not applicable for the arguments (PacketListener). What is wrong with this? I mean I know that the ? type is unknown and it usually disallows parameters of any type (or at least so I've read), but in the code the type argument extends PacketListener so I don't see the error.

The Packet class looks like this:

public interface Packet<T extends PacketListener>
{
    void encode(PacketDataSerializer packetdataserializer) throws IOException;

    void decode(PacketDataSerializer packetdataserializer) throws IOException;

    void handle (T listener);
}

And before assuming anything, no it's not Minecraft Server related, yes I helped myself with the naming and structure from the Minecraft Server source code (the one from bukkit/spigot servers).

EDIT:

Alright a comment got me thinking so I tested something and it's not a wildcard and it doesn't work...

private static <T extends PacketListener> void a(Packet<T> packet, PacketListener packetlistener) {
    packet.handle(packetlistener);
}
Alex Vasile
  • 33
  • 1
  • 6
  • Try `Packet super PacketListener>` – Rogue Nov 23 '19 at 22:05
  • It works but why can't I just leave the ? alone. I mean it's for sure something that extends PacketListener... – Alex Vasile Nov 23 '19 at 22:19
  • The short version has to do with covariance, contravariance, and the fact that the wildcard type in java (`>`) is covariant. You can assign a `?` to the upper bound, but you can't assign the upper bound to `?`. [This SO post has a couple of good top answers](https://stackoverflow.com/questions/2723397/what-is-pecs-producer-extends-consumer-super), but in general you're not going to be able to pass a class-level generic parameter to a wildcard type. – Rogue Nov 23 '19 at 22:53
  • @Rogue I edited my question with a different trial of a solution – Alex Vasile Nov 23 '19 at 23:20
  • Well, it's essentially the same problem. `T extends PacketListener` is a covariant bound, and you need a contravariant one. That or just a nonvariant `Packet`, and I could also remind you that you can pass a subclass of `PacketListener` to a method parameter which is just `PacketListener` (no generics). – Rogue Nov 23 '19 at 23:24
  • Alright, thanks, I just wanted to know why minecraft does it like that, now i'll find a convenient workaround – Alex Vasile Nov 23 '19 at 23:25

1 Answers1

2

Let's take a look at this code:

private static <T extends PacketListener> void a(Packet<T> packet,
                                                 PacketListener packetlistener) {
    packet.handle(packetlistener);
}

This calls the handle method on the packet object, which has type Packet<T>. This method's signature is defined in the Packet interface as:

    void handle (T listener);

So it accepts a parameter of type T. But you are calling it with the argument packetlistener, which has type PacketListener. That is, the argument's type is not T, because in general T can be some subtype of PacketListener, but you only provided the base type PacketListener.

The simplest fix is to require the packetlistener object to have the type T, so it can be accepted by the handle method:

private static <T extends PacketListener> void a(Packet<T> packet,
                           /* changed here -> */ T packetlistener) {
    packet.handle(packetlistener);
}
kaya3
  • 47,440
  • 4
  • 68
  • 97
  • Welp. Minecraft Servers are working weirdly, anyhow, I removed type parameters in general 'cuz I never actually wanted them, so I only added ` void handle (T listener);` – Alex Vasile Nov 24 '19 at 12:38