Apollo
Apollo

Reputation: 1005

Generic Type extends Interface but gets an incompatible type error

I am new to Java -- coming from the PHP Python world. I am sure this is a simple question and that I'm missing something basic, but after a couple hours of searching and tinkering, I can't figure it out.

I have a Path class that keeps to points, an In and an Out:

public class Path<In extends PointInterface, Out extends PointInterface> {
    private In in;
    private Out out;

    public Path(In in, Out out) {
        this.in = in;
        this.out = out;
    }

    public In getIn() {
        return in;
    }

    public Out getOut() {
        return out;
    }
}

I have many implementations of PointInterface, for now, let's say Queue and Endpoint.

I want to be able to instantiate a Path object with any combination of those two PointInterface implementations.

That's all pretty easy. Path path = new Path<>(new Endpoint(), new Queue());

The Problem Is that each of those implementations has its own handler for both In and Out. So, inside that EndpointInHandler I can be certain that path.getIn() will return an Endpoint (which implements PointInterface).

But, when I try Endpoint in = path.getIn(); inside that method, I get an Incompatible Types error saying that it required Endpoint but found PointInterface.

Endpoint implements PointInterface.

I have tried:

Can anyone help me understand what I'm missing? Much thanks :)

Code Sample

Inside my Main method:

Path path = new Path<>(new Endpoint(), new Queue());

InHandlerInterface handler = path.getIn().getInHandler(); // returns the EndpointInHandler
handler.handle(path);

Path detailed above.

PointInterface:

public interface PointInterface {
    InHandlerInterface getInHandler();
}

Endpoint:

public class Endpoint implements PointInterface {
    @Override
    public InHandlerInterface getInHandler() {
        return new EndpointInHandler();
    }

    public String specificToEndpoint() {
        return "Whatever";
    }
}

InHandlerInterface:

public interface InHandlerInterface {
    void handle(Path path);
}

EndpointInHandler:

public class EndpointInHandler implements InHandlerInterface {
    @Override
    public void handle(Path path) {
        Endpoint in = path.getIn(); // This is giving me the Incompatible types error

        String whatever = in.specificToEndpoint();
    }
}

Upvotes: 0

Views: 578

Answers (1)

Jai
Jai

Reputation: 8363

When you do Path path = new Path<>(new Endpoint(), new Queue()), you have effectively lost the type of the generics.

You need to write it as Path<EndPoint, Queue> path = new Path<>(new Endpoint(), new Queue()) so that the compiler is aware what the actual types the generics are referring.

Update

Looking again, I realized that you need to put generics everywhere. It may look weird to see generics appearing everywhere, but this is the way to ensure compile-time type safety. Doing this, you would not need any explicit casts.

Path<Endpoint, Queue> path = new Path<>(new Endpoint(), new Queue());

InHandlerInterface<Endpoint> handler = path.getIn().getInHandler(); // returns the EndpointInHandler
handler.handle(path);

PointInterface:

public interface PointInterface<T extends PointInterface> {
    InHandlerInterface<T> getInHandler();
}

Endpoint:

public class Endpoint implements PointInterface<Endpoint> {
    @Override
    public InHandlerInterface<Endpoint> getInHandler() {
        return new EndpointInHandler<>();
    }

    public String specificToEndpoint() {
        return "Whatever";
    }
}

InHandlerInterface:

public interface InHandlerInterface<T extends PointInterface<T>> {
    void handle(Path<T, ?> path);
}

EndpointInHandler:

public class EndpointInHandler implements InHandlerInterface<Endpoint> {
    @Override
    public void handle(Path<Endpoint, ?> path) {
        Endpoint in = path.getIn(); // This is naturally type safe, and compiler won't complain

        String whatever = in.specificToEndpoint();
    }
}

Upvotes: 2

Related Questions