2010-07-12 21 views
5

¿Cómo obtengo una referencia de todos los beans que implementan una interfaz genérica específica (por ejemplo, filtro <TestEvent>) en Spring?Obtener todos los beans implementando una interfaz genérica en Spring

Esto es lo que quiero lograr con un número mínimo de líneas:

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 
      } 
     } 
     //... 
    } 

} 

Mi implementación actual utiliza la reflexión para determinar si filter.approve ¿Acepta el evento antes de llamar. P. ej.

 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 
       } 
      } 
     } 

Cuando el doesFilterAcceptEventAsArgument hace todo el trabajo feo que me gustaría le gustaría alejarse de. ¿Alguna sugerencia?

Respuesta

2

Si su pregunta es "Spring tiene una manera más agradable de hacer esto", entonces la respuesta es "no". Por lo tanto, su método se ve como la forma omnipresente de lograr esto (obtener todos los beans de la clase sin procesar, luego usar el reflejo para buscar el límite genérico y compararlo con la clase del objetivo).

En general, el uso de información genérica en el tiempo de ejecución es complicado si es posible. En este caso, puede obtener los límites genéricos, pero en realidad no obtiene mucho beneficio de la definición genérica en sí, aparte de usarla como una forma de anotación para verificar manualmente.

En cualquier caso, tendrá que realizar algún tipo de control en el objeto devuelto, por lo que su bloque de código original no va a funcionar; la única variación se encuentra en la implementación de doesFilterAcceptEventAsArgument. La forma clásica OO, sería añadir una superclase abstracta con dos métodos de la siguiente manera (y añadir ésta a la interfaz de filtro):

protected abstract Class<E> getEventClass(); 

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

Este es un tipo de dolor, ya que tendrá que poner en práctica lo trivial getEventClass() métodos en cada implementación para devolver el literal de clase apropiado, pero es una limitación conocida de los genéricos. Dentro de los límites del lenguaje, este es probablemente el enfoque más limpio.

Pero la tuya está bien por lo que vale.

+0

Gracias, tal como sospechaba. –

4

Sólo como referencia, la solución más sencilla que pude construir era la siguiente:

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){ } 
    } 

y funcionó bastante bien para la creación de prototipos.

Cuestiones relacionadas