2012-02-11 21 views
28

tengo una fábrica como abajo,parámetro Pass para el constructor con Guice

public final class Application { 

    private static IFoo foo; 

    public static IFoo getFoo(String bar) 
    { 
      // i need to inject bar to the constructor of Foo 
      // obvious i have to do something, not sure what 
     Injector injector = Guice.createInjector(); 
     logger = injector.getInstance(Foo.class); 
     return logger;    
    } 

} 

Ésta es la definición de Foo:

class Foo 
{ 
    Foo(String bar) 
    { 

    } 

} 

OK. No estoy seguro de cómo puedo pasar este parámetro al constructor de Foo con Guice?

¿Alguna idea?

Respuesta

43

Todas las respuestas de "Guice Constructor Parameter" parecen estar incompletas de alguna manera. Aquí es una solución completa, que incluye el uso de:

interface FooInterface{ 
    String getFooName(); 
} 

// Anotar el constructor y los parámetros asistidos en la clase de implementación

class Foo implements FooInterface { 
    String bar; 

    @Inject 
    Foo(@Assisted String bar) 
    { 
     this.bar = bar; 
    } 

    // return the final name 
    getFooName(){ 
    return this.bar; 
    } 

} 

// Crear una interfaz de fábrica con un método create() que toma solo los parámetros asistidos. // FooFactory interfaz no tiene una clase de implementación explícita (Guice magia)

interface FooFactory{ 
    Foo create(String bar); 
} 

// Enlazar esa fábrica a un proveedor creado por AssistedInject

binderModule implements Module{ 

void configure(Binder binder) { 
    binder.install(new FactoryModuleBuilder() 
     .implement(FooInterface.class, Foo.class) 
     .build(FooFactory.class)); 
} 
} 

// Ahora usarlo:

class FooAction{ 

    @Inject private FooFactory fooFactory; 

    doFoo(){ 
     // Send bar details through the Factory, not the "injector" 
     Foo f = fooFactory.create("This foo is named bar. How lovely!"); 
     f.getFooName(); // "This foo is named bar. How lovely!" 
    } 
} 

Un montón de ayuda aquí: https://google.github.io/guice/api-docs/latest/javadoc/index.html?com/google/inject/assistedinject/FactoryModuleBuilder.html

+0

No funciona para mí. Tengo * NullPointerException * porque el constructor * Foo * nunca llamó. ¿Probablemente necesites usar tu * Módulo * en alguna parte? –

+0

Corrija el tipo de devolución faltante del método "crear" (interfaz FooFactory). Debe ser: Foo create (String bar); – frhack

1

Si esta clase es una fábrica, debe ser un objeto administrado-Guice, tener un método getFoo no estática, y el método getFoo sería sólo tiene que utilizar

new Foo(bar) 

No todas las clases debe ser instanciado por Guice .

También vea AssistedInject, para evitar crear esta fábrica usted mismo y deje que Guice cree una para usted.

8

Lo que probablemente esté buscando es utilizar una fábrica de Guice. Particularmente fácil con la funcionalidad AssistedInject, pero tienen un manual example at the top of the page. En resumen, para el ejemplo de manual es que obtienes la fábrica en el método getFoo no estático que pasas los parámetros que necesites y construyes el objeto desde allí.

Esto no funcionará directamente si tiene interceptación de métodos en Foo, pero funcionará en muchos otros casos.

Para utilizar AssistedInject, que para mí tiene una semántica algo más limpios y menos significa cableado manual, debes contar con la extensión guice-assistedinject en la ruta de clase, a continuación, al crear Foo (bueno, FooImpl, debemos utilizar las interfaces):

@Inject 
public FooImpl(@Assisted String bar) 
{ 
    this.baz = bar; 
} 

a continuación, crear una interfaz FooFactory:

public interface FooFactory { 
    public Foo create(String bar); 
} 

Luego, en su módulo guice:

install(new FactoryModuleBuilder() 
    .implement(Foo.class, FooImpl.class) 
    .build(FooFactory.class)); 

Puede consultar el javadoc for FactoryModuleBuilder para obtener ejemplos de fábricas más complejas.

+0

sí, es una mierda, es tan intrincado, structuremap es mucho más flexible que guice. – DarthVader

+0

¿Dónde puedo descargar StructureMap para Java? – mark

+0

Esto funcionó para mí, aunque no es muy bonito. –

4

sé tha Esto es un hilo viejo, pero hoy mismo me tocó el tema. Solo necesito dos o tres instancias diferentes de 'Foo' y realmente no quería escribir todo el código de fábrica de la placa base. Con un poco de google encontré esto Stubbisms – Tony’s Weblog Sugeriría esta solución que es perfecta si sabe exactamente qué instancias necesita.

En el módulo Guice:

bind(Foo.class).annotatedWith(Names.named("firstFoo")).toProvider(new Provider<Foo>() { 
     @Override 
     public Foo get() { 
      return new FooImpl("topic A"); 
     } 
    }); 
    bind(Foo.class).annotatedWith(Names.named("secondFoo")).toProvider(new Provider<Foo>() { 
     @Override 
     public Foo get() { 
      return new FooImpl("topic B"); 
     } 
    }); 

O en Java 8:

bind(Foo.class).annotatedWith(Names.named("firstFoo")).toProvider(() -> new FooImpl("first")); 
    bind(Foo.class).annotatedWith(Names.named("secondFoo")).toProvider(() -> new FooImpl("second")); 

Y en el constructor de su servicio donde se necesita instancias de Foo:

@Inject 
public MyService (
    @Named("firstFoo") Foo firstFoo, 
    @Named("secondFoo") Foo secondFoo) { 
} 

Y Foo en mi caso:

public class FooImpl implements Foo { 

    private String name; 

    public FooImpl(String name) { 
     this.name = name; 
    } 

    @Override 
    public String getName() { 
     return name; 
    } 
} 

Espero que ayude a alguien.

Cuestiones relacionadas