0

I have two types(T,M) first one is recognized by the compiler second one isnt. any idea what am i doing wrong?

public class SendMessageResponse<T> {

    private T result;
}

public class MessageResponse<M> {

    private M message;
}

interface is defined this way:

public interface EventQueue<T, M> {

    SendMessageResponse<T> send(String address, String message, String eventId);

    void consumeBatch(String address, int numOfConsumersPerQueue, Handler<MessageResponse<M>> callback);

    ..
}

on impl:

public class EventQueueSQS
        implements EventQueue<SendMessageResultImpl, MessageImpl> {

    @Override
    public SendMessageResponse send(String address, String message, String eventId) {..}

    @Override
    public void consumeBatch(String address, int numOfConsumerThreads, Handler<MessageResponse> callback) {
    }

    ..
}

for the consumeBatch override method i have complication error:

Error:(164, 17) java: name clash: consumeBatch(java.lang.String,int,io.vertx.core.Handler<java.util.List<MessageResponse>>) in EventQueueSQS and consumeBatch(java.lang.String,int,io.vertx.core.Handler<java.util.List<MessageResponse<M>>>) in EventQueue have the same erasure, yet neither overrides the other

compiler force me on the method to write the impl:

public void consumeBatch(String address, int numOfConsumersPerQueue, Handler<MessageResponse<Message>> callback) {

why? I have declared it on the class level

any idea?

Perhaps the issue that Iam using Handler which holds class that has generics? I cant find the diff between SendMessageResponse or using Handler> regarding generics as the first one works and the other one doesnt

rayman
  • 20,786
  • 45
  • 148
  • 246
  • Did you see https://stackoverflow.com/questions/14002965/java-name-clash-have-the-same-erasure-neither-hides-the-other? –  Dec 24 '17 at 10:40
  • iam not sure how this questions is related to my question? as iam implementing interface with generics. and compiler doesnt like the second method – rayman Dec 24 '17 at 11:57

3 Answers3

0

When compiled to bytecode type parameters such as M are transformed to their bound implementation type if bounded or Object if unbounded see this.Since you provide no implementation type in the method of your class EventQueueSQS, both the interface method and the class method are compiled to Handler<MessageResponse<Object>> which creates a clash error. So you need to provide-bind an implemented type for your type parameter M in your class method,which in your case is MessageImpl.

If you dont want to provide an actual implementation type in your class EventQueueSQS either remove <M> from Handler<MessageResponse<M>> in the interface, or make your class also parameterized like EventQueueSQS<T,M> implements EventQueue<T,M> where you still have to provide it inside your method's argument but as a parameter M, and this way you can create instances like EventQueueSQS<SendMessageResultImpl,MessageImpl>.

ichantz
  • 298
  • 3
  • 11
  • how would you solve it? coz I did provide impl. look at my EventQueueSQS, it users M as MessageImpl – rayman Dec 24 '17 at 15:44
  • why SendMessageResponse didnt throw any errors? I have treated it the same way – rayman Dec 24 '17 at 15:44
  • What i believe happened is that when you pass in MessageImpl when you implement the interface and then you override the consumeBatch function, MessageIml is expected to be passed as type to MessageResponse because of the signature of the interface (the second type M is expected also at that point)....so when it is compiled it sees Handler> instead of Handler> which is expected. This breaks the signature but in the case of SendMessageResponse both in the interface and the class are compiled to SendMessageResponse which is fine. – ichantz Dec 25 '17 at 01:57
  • there is no way to use on my impl class(EventQueueSQS) the method this way:public void consumeBatch( String address, int numOfConsumerThreads, Handler callback) ? how would you modify the code to achieve this – rayman Dec 26 '17 at 08:03
  • If you dont want to provide an actual implementation type in your class `EventQueueSQS` either remove `` from `Handler>` in the interface, or make your class also parameterized like `EventQueueSQS implements EventQueue` where you still have to provide it inside your method's argument but as `M`, and this way you can call create instances like `EventQueueSQS` . – ichantz Dec 26 '17 at 11:56
  • can you please add to your answer your last comment suggestion as a code example? could help others as well. thank you! – rayman Dec 26 '17 at 15:01
0

In your method you set the argument type:

Handler<MessageResponse> callback

But this is the same as

Handler<MessageResponse<Object>> callback

and this does conflict with your type M which is MessageImpl. If you are using a Java version supporting the diamond operator, it may allow you to write Handler<MessageResponse<>> callback which is the same as the compiler-suggested one.

J Horseman
  • 318
  • 2
  • 12
  • iam not sure where i should use Handler> on the interface or on the implementing class (EventQueueSQS) – rayman Dec 24 '17 at 15:46
  • but look at my other method which using SendMessageResponse. it compiles perfect. what is the diff? – rayman Dec 24 '17 at 15:59
0

Here is your concrete implementation:

public class EventQueueSQS
    implements EventQueue<SendMessageResultImpl, MessageImpl> {

    @Override
    public SendMessageResponse send(String address, String message, String eventId) {..}

    @Override
    public void consumeBatch(
            String address, 
            int numOfConsumerThreads, 
            Handler<MessageResponse> callback) {
    }

    ..
}

According to your interface definition, this is not an appropriate match for the signature of your consumeBatch method. You need:

    public void consumeBatch(
            String address, 
            int numOfConsumerThreads, 
            Handler<MessageResponse<MessageImpl>> callback) {
    }
scottb
  • 9,908
  • 3
  • 40
  • 56
  • why do I need to set my concrete impl with Handler> - I already set it on the class level defined what is M type. why its not the same situation as with SendMessageResponse where I could keep it SendMessageResponse on the override method without mention there the T type – rayman Dec 24 '17 at 17:26
  • The Handler type in your concrete implementation must be defined as shown because that is how you have defined it. It's a good thing too. Generics are a compile-time only phenomenon in Java 9. Unbounded generic types are erased to `Object` at run time. The only way the compiler can guarantee the type safety of your program is if you assure it that your concrete method can accept only the type(s) that be resolved through your type declarations. Here, `M` is an unbounded type, so you can only specify `Handler>` and maintain the compiler guarantee of type safety. – scottb Dec 24 '17 at 18:46
  • so in this case why have I bounded it on the class level? and why I dont need to bound SendMessageResponse into T on my concrete impl aswell? – rayman Dec 24 '17 at 18:57
  • Your formal generic type declarations use only unbounded type parameters. i don't understand your question. – scottb Dec 24 '17 at 19:01
  • look at the first method: public SendMessageResponse... the compiler didnt complain on it. however on this one: public void consumeBatch(String address, int numOfConsumerThreads, Handler callback) it did complain. SendMessageResponse which is T type passed without errors in contrast to the Handler callback. any idea why? – rayman Dec 24 '17 at 20:50