2010-07-12 40 views
5

Come ottengo un riferimento di tutti i bean che implementano un'interfaccia generica specifica (ad esempio, il filtro <TestEvent>) in primavera?Ottieni tutti i bean che implementano un'interfaccia generica in primavera

Questo è ciò che voglio raggiungere con un numero minimo di linee:

public interface Filter<T extends Event> { 

    boolean approve(T event); 

} 


public class TestEventFilter implements Filter<TestEvent> { 

    public boolean approve(TestEvent event){ 
     return false; 
    } 

} 

public class EventHandler{ 
    private ApplicationContext context; 

    public void Eventhandler(DomainEvent event) { 
     // I want to do something like following, but this is not valid code 
     Map<String, Filter> filters = context.getBeansOfType(Filter<event.getClass()>.class); 
     for(Filter filter: filters.values()){ 
      if (!filter.approve(event)) { 
       return; // abort if a filter does not approve the event 
      } 
     } 
     //... 
    } 

} 

mio attuale implementazione utilizza la riflessione per determinare se filter.approve non accetta l'evento prima di chiamare. E.g.

 Map<String, Filter> filters = context.getBeansOfType(Filter.class); 
     for(Filter filter: filters.values()){ 
      if (doesFilterAcceptEventAsArgument(filter, event)) { 
       if (!filter.approve(event)) { 
        return; // abort if a filter does not approve the event 
       } 
      } 
     } 

Qualora la doesFilterAcceptEventAsArgument fa tutto il lavoro brutto che vorrei vorrebbe allontanarsi da. Eventuali suggerimenti?

risposta

2

Se la tua domanda è "la primavera ha un modo migliore per farlo", la risposta è "no". Quindi, il tuo metodo sembra il modo onnipresente per ottenere questo risultato (prendi tutti i bean della classe raw, quindi usa reflection per cercare il limite generico e confrontalo con la classe target).

In generale, l'utilizzo di informazioni generiche in fase di esecuzione è complicato se possibile. In questo caso è possibile ottenere i limiti generici, ma non si ottiene realmente molto beneficio dalla definizione generica stessa, oltre a utilizzarlo come una forma di annotazione da verificare manualmente.

In ogni caso, è necessario eseguire del tipo di controllo sull'oggetto restituito, quindi il blocco di codice originale non funzionerà; l'unica variazione è nell'implementazione di doesFilterAcceptEventAsArgument. Il modo OO classico, sarebbe quella di aggiungere un superclasse astratta con due modi, come segue (e aggiungere quest'ultimo all'interfaccia Filter):

protected abstract Class<E> getEventClass(); 

public boolean acceptsEvent(Object event) // or an appropriate class for event 
{ 
    return getEventClass().isAssignableFrom(event.getClass()); 
} 

Questa è una specie di dolore in quanto si dovrà implementare la banale getEventClass() metodi in ogni implementazione per restituire il letterale di classe appropriato, ma è un limite noto di generici. Entro i limiti della lingua, questo è probabilmente l'approccio più pulito.

Ma il tuo va bene per quello che vale.

+0

Grazie, proprio come sospettavo. –

4

Solo per riferimento, la soluzione più semplice che potrei costruire è stato questo:

Map<String, Filter> filters = context.getBeansOfType(Filter.class); 
    for(Filter filter: filters.values()){ 
     try { 
      if (!filter.approve(event)) { 
       return; // abort if a filter does not approve the event. 
      } 
     } catch (ClassCastException ignored){ } 
    } 

e ha funzionato abbastanza bene per la prototipazione.

Problemi correlati