My question is about implementing different behaviours for different messages in an as extensible way as possible. I am aware of the visitor pattern, I am aware of double-dispatch, but I can't seem to figure out a solution, which satiesfies me (not within the limits of java at least).
My situation is as follows:
I have a hierarchy of Messages:

and a hierarchy of router-interfaces, each defining a route method for its own message-type:

which I would like to implement similar to this:

to be able to add and remove the capability to route certain messages, as well as to change routing-strategies for certain messages easily.
The problem is, that without switch-casting my message, which I don't want to do, I cannot select the respective function for the interface, because something like
CompositeRouter comp = new AllRouter(...//new Router instances);
MessageBase msg = new DerivedMessage();
msg.process(comp);
will lead to java selecting the overload <runtime message-type>.process(Router)
at compile time, which, at runtime, is invoked for the respective router object. So I cannot select the right calls to process() at compile time it seems. I can also not do it the other way round, because comp.route(msg)
will be resolved to <dynamic router-type>.route(MessageBase). 
I could write a visitor, which selects the proper method from CompositeRouter, but therefor I would have to define the visitor interface with the respective route-Methods defined for all the MessageTypes up front, which kind of defeats the purpose, because it means that I have to rewrite the visitor whenever I add a new DerivedMessage.
Is there a way to implement this such that both Message and Router are extensible or is it hopeless given the current java-features?
Edit 1:
Something I forgot to mention is that I have 4 or 5 other situations, which are pretty much the same as the Router-hierarchy, so I kind of want to avoid Reflection for method-lookup, because I am afraid of the runtime-cost. 
Response to comments:
@aruisdante's assumption regarding @bot's suggestion is correct. I cannot Override, because I would loose the runtime-type of MessageBase, if I override route(MessageBase).
@aruisdante and @geceo: I know that I can do that - this what I meant with "switch-casting" (MessageBase has a MessageType field) - but I have like 11 actual message classes and ~6 locations in code where I need it, so it would be a HUGE pain implementation- as well as maintenance-wise.
Here is how I've typically solved problems like this in the past:
First, in your Router interface, since it seems you intend most Router implementations with the exception of the Composite to handle only a single message type, change the definition of the interface to something similar to:
interface Router<T extends MessageBase> {
    void route(T message);
}
This removes the need to provide interfaces for the various Routers that handle specific implementations. Your derived Router classes then become something like:
class OtherDerivedRouter implements Router<OtherDerivedMessage> {
    @Override
    void route(OtherDerivedMessage message) { //... };
}
So now what happens in CompositeRouter? Well, we do something like this:
class CompositeRouter implements Router<MessageBase> {
    protected static class RouterAdaptor< T extends MessageBase> implements Router<MessageBase> {
         private Router<T> router;
         private Class<T>  klass;
         RouterAdaptor(Router<T> router, Class<T> klass) {
             this.router = router;
             this.klass  = klass;
         }
         @Override
         public void route(MessageBase message) {
            try {
                router.route(klass.cast(message));
            } (catch ClassCastException e) {
                // Do whatever, something's gone wrong if this happens
            }
         }
     }
     private Map<Class<?>, RouterAdaptor<?>> routerMap;
     @Override
     public void route(MessageBase message) {
         RouterAdaptor<?> adaptor = routerMap.get(message.getClass());
         if (adaptor != null) {
             adaptor.route(message)
         } else {
           // do your default routing case here
         }
     }
     public <T extends MessageBase> void registerRouter(Router<T> router, Class<T> klass) {
         // Right now don't check for overwrite of existing registration, could do so here
         routerMap.put(klass, new RouterAdaptor<T>(router, kass));
     }
     CompositeRouter(/*...*/) {
         //initialize routerMap with Map type of choice, etc
     }
}
The RouterAdaptor does the heavy lifting of dispatching the correct message type expected by the Router implementation it holds. And leaves CompositeRouter needing only to store a registry of these adaptors to their message type.
The biggest downside of this approach is that, thanks to Type Erasure, there is no way to create a Router implementation that handles more than one message type by itself directly. From Java's prospective, at runtime Router<MessageBase> is the same as Router<OtherDerivedMessage>, and thus it is illegal to have something like SuperRouter implements Router<MessageBase>, Router<OtherDerivedMessage>, unlike you could with C++ templates. This is also why you need to pass explisit Class<T> objects around rather than just being able to infer the type directly from Router<T>.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With