2015-01-30 15 views
6

Sono diventato molto affezionato a Google Gauva's EventBus, tanto che desidero includerlo in una delle mie API Swing GridBagBuilder. L'obiettivo è prendere un componente Swing e fare qualcosa con esso in un evento arbitrario e iscriverlo a un EventBus. Il problema è che penso che le operazioni di riflessione effettuate da EventBus non piacciano ai miei generici per qualsiasi tipo di evento arbitrario.Passare un evento generico a Guava EventBus?

In sostanza, il metodo accetta un BiConsumer in cui C è un componente Swing ed E è un tipo di evento arbitrario da sottoscrivere a EventBus.

public <E> void subscribe(EventBus eventBus, BiConsumer<C,E> consumer) { 
    eventBus.register(new Object() { 
     @Subscribe 
     public void processEvent(E event) { 
      try { 
      consumer.accept(comp, event); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    }); 
} 

Il bus evento sembra funzionare, ma continuo a ricevere bizzarre ClassCastException errori. C'è un modo per far funzionare questo? O è quello che sto cercando di ottenere una causa persa?

AGGIORNAMENTO: qui è un SSCCE. Si interrompe quando ci sono più tipi di eventi e da qualche parte i meccanismi generici e di riflessione interna vengono incasinati e non è in grado di distinguere un tipo di evento da un altro.

import java.awt.Component; 
import java.util.function.BiConsumer; 

import javax.swing.JButton; 

import com.google.common.eventbus.EventBus; 
import com.google.common.eventbus.Subscribe; 

public class EventBusTest<C extends Component> { 
    private final C comp; 

    public static void main(String[] args) { 
     final EventBus eventBus = new EventBus(); 

     EventBusTest<JButton> test = new EventBusTest<>(new JButton("Hello")); 
     test.subscribe(eventBus, (JButton c, SomeEvent e) -> System.out.println("Hello")); 
     test.subscribe(eventBus, (JButton c, SomeOtherEvent e) -> System.out.println("World")); 

     eventBus.post(new SomeEvent()); 
    } 

    private EventBusTest(C comp) { 
     this.comp = comp; 
    } 
    public<E> void subscribe(EventBus eventBus, BiConsumer<C,E> consumer) { 
     eventBus.register(new Object() { 
      @Subscribe 
      public void processEvent(E event) { 
       try { 
       consumer.accept(comp, event); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 
    } 

    private static final class SomeEvent {} 
    private static final class SomeOtherEvent {} 
} 

E qui è la stampa console ...

java.lang.ClassCastException: com.swa.rm.pricing.EventBusTest$SomeEvent cannot be cast to com.swa.rm.pricing.EventBusTest$SomeOtherEvent 
    at com.swa.rm.pricing.EventBusTest$$Lambda$14/28594521.accept(Unknown Source) 
    at com.swa.rm.pricing.EventBusTest$1.processEvent(EventBusTest.java:32) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
    at java.lang.reflect.Method.invoke(Unknown Source) 
    at com.google.common.eventbus.EventSubscriber.handleEvent(EventSubscriber.java:74) 
    at com.google.common.eventbus.SynchronizedEventSubscriber.handleEvent(SynchronizedEventSubscriber.java:47) 
    at com.google.common.eventbus.EventBus.dispatch(EventBus.java:322) 
    at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:304) 
    at com.google.common.eventbus.EventBus.post(EventBus.java:275) 
    at com.swa.rm.pricing.EventBusTest.main(EventBusTest.java:21) 
Hello 
+0

Mostrare un esempio completo e riproducibile che mostri un 'ClassCastException' e pubblichi la traccia dello stack completo. –

+0

Dang, il SSCCE che ho costruito funziona. Perché...? – tmn

+0

Ok, è stato rotto! Si interrompe quando ci sono più tipi di eventi. Aggiornamento sopra ... – tmn

risposta

3

Il parametro type E nel anonima Object sottoclasse in subscribe() sarà sempre cancellato, dal momento che non v'è alcun tipo concreto a reificare esso. La cancellazione di E è solo Object, quindi nulla impedisce al tuo metodo processEvent() di essere chiamato con qualsiasi tipo.

Per risolvere questo problema, è necessario passare un tipo di token (Class<E> sarà probabilmente sufficiente) e utilizzarlo per verificare che il tipo di runtime è in realtà E prima di invocare il BiConsumer callback.

Problemi correlati