2009-02-26 27 views
12

me gustaría lograr algo similar a la siguiente en Guice:Inyectar una matriz de objetos en Guice

public MyClass { 

    private final InjectedObject[] injectedObjects; 

    @Inject 
    public MyClass(InjectedObject[] injectedObjects) { 
     this.injectedObjects=injectedObjects; 
    } 
} 

es decir, me gustaría ser capaz de crear un cierto número de instancias de un objeto, e inyectar ellos en otro objeto como una matriz. Probablemente podría hacer esto en su lugar:

public MyClass { 

    private final InjectedObject[] injectedObjects; 

    @Inject 
    public MyClass(InjectedObjectProvider injectedObjectProvider) { 
     this.injectedObjects=injectedObjectProvider.getArrayOfInjectedObjects(5); 
    } 
} 

... pero me preguntaba si había otra ruta que fuera más elegante?

Respuesta

8

Tengo curiosidad por qué quieres varios objetos creados con entusiasmo. Puede tener éxito inyectando un Provider<InjectedObject> y llamando al Provider.get() cada vez que necesite una instancia. Si realmente necesita 5, se podría construir 'em en un bucle:

public MyClass { 
    private final List<InjectedObject> injectedObjects; 

    @Inject 
    public MyClass(Provider<InjectedObject> injectedObjectProvider) { 
    injectedObjects = new ArrayList<InjectedObject>(); 
    for (int i = 0; i < 5; i++) { 
     injectedObjects.add(injectedObjectProvider.get()); 
    } 
    } 
} 
+0

Gracias por la sugerencia - la razón de tener varias proporcionan impaciencia es ser capaz de colocar en un ThreadPool: el número de instancias en el grupo dependerá de la cantidad de núcleos disponibles. – Rich

+0

¿Cómo harías esto si no tuvieras el control del código fuente de MyClass, pero solo deseas inyectarlo usando enlaces y otro código en la configuración del Módulo (preferiblemente sin usar Multibindings ya que no es compatible con Gin)? – Snekse

+0

Snekse, podría crear un método @Provides que tome el proveedor como parámetro y llame al constructor MyClass al final. –

8

Una opción sería la de inyectar un Provider<InjectedObject> en su clase, como se ha mencionado Jesse:

public class MyClass { 
    private final List<InjectedObject> injectedObjects; 

    @Inject 
    public MyClass(Provider<InjectedObject> injectedObjectProvider) { 
    List<InjectedObject> objects = new ArrayList<InjectedObject>(); 
    for (int i = 0; i < 5; i++) { 
     objects.add(injectedObjectProvider.get()); 
    } 
    injectedObjects = Collections.unmodifiableList(objects); 
    } 
} 

Hacer esto puede ser problemático . Si InjectedObject tiene un ámbito de @Singleton o @RequestScoped, cada vez que llame al injectedObjectProvider.get() obtendrá la misma referencia. Otro problema con la inyección de un Provider para hacer esto es que no sería claro desde la API que MyClass depende de varias instancias de InjectedObject. Finalmente, ha codificado en MyClass que debe inyectarse con cinco instancias.

Es raro que necesite inyectar un Provider en un objeto. Usualmente cuando hago esto, es porque el alcance del objeto actual significa que tendrá una vida más larga que el alcance del objeto dependiente (por ejemplo, un @Singleton que necesita acceso a un objeto @RequestScoped).

En lugar de la inyección de un Provider, se puede inyectar un List<InjectedObject> en el constructor, y crear un método proveedor en un módulo de Guice:

@Provides 
MyClass prividesMyClass(Provider<InjectedObject> injectedObjectProvider) { 
    List<InjectedObject> objects = new ArrayList<InjectedObject>(); 
    for (int i = 0; i < 5; i++) { 
    objects.add(injectedObjectProvider.get()); 
    } 
    return new MyClass(objects); 
} 

(que podría, por supuesto, se unen mediante un TypeLiteral)

¿Por qué es esto mejor? Aunque todavía está codificando cinco objetos en este código, no está codificado en MyClass, por lo que los clientes de MyClass (incluidas las pruebas para MyClass en sí) pueden elegir construir el objeto de diferentes maneras.

Si la codificación dura de este conocimiento en un módulo de Guice no es una buena idea, en su lugar puede crear una interfaz que tiene un contrato más específico que Provider

public interface InjectedObjectRepository { 
    List<InjectedObject> getInjectedObjects(); 
} 

Incluso si usted decide que quiere MyClass para ser responsable de saber cuántas instancias crear, es posible que desee crear una interfaz (quizás llamada InjectedObjectSupplier para poder documentar explícitamente que espera una instancia única cada vez.

+0

Me gusta esta respuesta, pero ¿cómo harías si quisieras que cada uno de los 5 'InjectedObject's fueran diferentes impls administrados por Guice? Ejemplo: 'bind (InjectedObject.class) .annotatedWith (AnnotA.class) .Para (ImplA.class) .En (Singleton.class);' ' bind (InjectedObject.class) .annotatedWith (AnnotB.class) .to (ImplB.class) .in (Singleton.class); ' – Snekse

+0

@Snekse Puede hacer lo que quiera con un método de proveedor (un método anotado con' @ Provides') – NamshubWriter

+0

Así que estoy claro, quiere decir que tiene 5 métodos de proveedor? 'provideImplA()', 'provideImplB()', etc ... ???? – Snekse

15

No estoy seguro si esto satisface sus necesidades, pero Multibindings funcionó para mí cuando necesitaba inyec t elementos múltiples del mismo tipo (sin embargo, produce un conjunto).

+0

Multibindings produce Conjuntos que están ordenados (la iteración sobre los elementos es la misma que la de los elementos de orden ligados al Multibinder). Esto significa que los Conjuntos producidos por Multibinding a menudo son tan buenos como una Lista o una matriz. –

1

Agregando esta respuesta para que las personas sepan cómo inyectar una matriz, ya que esto aparece primero en una búsqueda en Google. Creo que cualquiera de estos funcionará:

En configure de un módulo: bind(InjectedObject[].class).toInstance(someArray); o como un método Proveedor:

@Provides 
InjectedObject[] getInjectedObject(@Inject Provider<InjectedObject> provider) { 
    InjectedObject[] objects = new InjectedObject[5]; 
    for (int i = 0; i < objects.length; i++) { 
    objects[i] = provider.get(); 
    } 
} 
Cuestiones relacionadas