Results 1 to 5 of 5
  1. #1
    CChange is offline Member
    Join Date
    Mar 2010
    Posts
    11
    Rep Power
    0

    Lightbulb Proper generics approach for the following design

    Hi!

    I am writing a little messagebus, which distributes messages based on the messageclass. The messagebus consists of a number of messageChannels, each for a certain type of message.

    Java Code:
    public abstract class MessageChannel<T extends Message> {
    	List<MessageReceiver<T>> messageReceivers=Collections.synchronizedList(new ArrayList<MessageReceiver<T>>());
    	Class<T> messageClass;
    	
    	public MessageChannel(Class<T> messageClass)
    	{
    		this.messageClass=messageClass;
    	}
    	
    	public void registerReceiver(MessageReceiver<T> messageReceiver)
    	{
    		messageReceivers.add(messageReceiver);
    	}
    
    	public boolean publishMessage(T message)
    	{
    		..	
         }
    }
    Java Code:
    public interface MessageReceiver<T extends Message> {
    	public boolean messageDelivery(T message);
    	public Class<T> getMessageClass();
    }
    "Problem"class:

    Java Code:
    public abstract class MessageBus 
    {
    	Map<Class<? extends Message>, MessageChannel<?>> messageChannels=Collections.synchronizedMap(new HashMap<Class<? extends Message>, MessageChannel<? extends Message>> ());
    	
    	public void addMessageChannel(MessageChannel<? extends Message> channel)
    	{
    		messageChannels.put(channel.getMessageClass(), channel);
    	}
    	
    	public void registerReceiver(MessageReceiver<? extends Message> receiver)
    	{
    		MessageChannel<? extends Message> channel=messageChannels.get(receiver.getMessageClass()); 
    		if(channel!=null) {
    			channel.registerReceiver( receiver); //This is the problem line, compile error see further down
    		}
    	}
    }
    These are my three classes, and in the last one (MessageBus) I am getting one of those generics compile errors. I read up about generics and I think the problem here is the "MessageBus" as it does not specify any generic parameters. I read that if one uses "? extends Message" one can only access that object as Message, ie only those methods (obviously). And I think because I try to pass this on to a method in a generically parameterized class (registerReceiver(..)) Java complains, because it kindof needs to upgrade to a more specified state of the class. If you know what I mean.

    Anyway, what is the correct pattern here? For now I will remove all generics use from Messagebus, but it d be nice to see how it works.

    Thanks!!

    ps.: Exact compile error message:
    The method registerReceiver(MessageReceiver<capture#7-of ? extends Message>) in the type MessageChannel<capture#7-of ? extends Message> is not applicable for the arguments (MessageReceiver<capture#8-of ? extends Message>) MessageBus.java

    pps.: I think logically it should work, otherwise why can I get the MessageReceiver out of the map without problems?
    Last edited by CChange; 12-04-2010 at 12:09 PM.

  2. #2
    couling is offline Member
    Join Date
    Nov 2010
    Posts
    54
    Rep Power
    0

    Default

    No this is not possible. Generics are there to ensure type safety.

    You're trying to add a MessageReciever for an unknown Message type to a MessageChannel for a completely different Unknown message type. Java is telling you that it can't be sure what will happen.

    Effectively you're throwing all your MessageChannels of every Message type into a bag (and shaking it around a bit). When someone wants to add a MessageReciever you rummage round in the bag, pull out the one you think is right and try to add the listener to it without any garuntee from Java that you got the right MessageChannel.

    I wonder if you really need an abstract message bus like this. I can see there are possible (though un-common) reasons why you might. If you do then you simply need to force it through by doing something like type casting. You need to forcably tell Java you got it right even through java can't be sure.
    Last edited by couling; 12-04-2010 at 09:24 PM. Reason: My gramma sucks
    ----Signature ----
    Please use [CODE] tags and indent correctly. It really helps when reading your code.

  3. #3
    CChange is offline Member
    Join Date
    Mar 2010
    Posts
    11
    Rep Power
    0

    Default

    Cheers mate!

    Though I have to say that "bag" example is not quite right. The shortcoming is actually that Java does nothing about the generics at runtime. Conceptually I believe all this is logical because the channel and the listener are bound by the extension of Message class. (Class<T> getMessageClass() of course returns the what is defined by the generic parameter which is then used to register the listener).

    So, how would you approach this, if you wanted a single messagebus to send and receive messages, rather than addressing each channel seperately?

    Would you, in a sense, go for:

    messageBus.getChannel(MyMessage.class).registerLis tener(this); //or whatever

    Thanks for your help and opinions!
    CC

  4. #4
    couling is offline Member
    Join Date
    Nov 2010
    Posts
    54
    Rep Power
    0

    Default

    I'm more used to seeing the getChannel approach. It means that if you add extra functionality to a MessageChannel you dont have to add extra functions to pass this through MessageBus. Note that getChannel may not remove the need to cast. At some point you need to cast from a MessageChannel<? extends Message> to a MessageChannel<Specific>.

    If you still really want the functions to work as you've laid out, you could allways just remove generics internally in the function, but keep them for the function prototypes:
    Java Code:
    	@SuppressWarnings("unchecked")
    	public void registerReceiver(MessageReceiver<? extends Message> receiver)
    	{
    		@SuppressWarnings("rawtypes")
    		MessageChannel channel=messageChannels.get(receiver.getMessageClass()); 
    		if(channel!=null) {
    			channel.registerReceiver( receiver);
    		}
    	}
    This is actually a really good example of the reason Generics did not completely remove the need to cast some times.


    Hope this helps
    ----Signature ----
    Please use [CODE] tags and indent correctly. It really helps when reading your code.

  5. #5
    CChange is offline Member
    Join Date
    Mar 2010
    Posts
    11
    Rep Power
    0

Similar Threads

  1. design & generics for socket server
    By gilme in forum New To Java
    Replies: 1
    Last Post: 06-18-2010, 05:24 AM
  2. design approach for multi-lingual gui
    By j2me64 in forum AWT / Swing
    Replies: 1
    Last Post: 05-14-2010, 06:54 PM
  3. Regex approach
    By karlito in forum Lucene
    Replies: 1
    Last Post: 11-04-2009, 06:53 PM
  4. Please suggest me the correct approach!
    By rjuyal in forum Advanced Java
    Replies: 6
    Last Post: 05-05-2008, 03:54 PM
  5. Opinions on best approach for objects
    By spikey in forum Advanced Java
    Replies: 1
    Last Post: 04-11-2008, 06:20 PM

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •