2017-02-03 2 views
3

exemple Toy:Comment faire pour déplacer un fournisseur anonyme qui référence des champs dans le module dans une classe distincte?

public class MyModule extends AbstractModule { 
    private static final Foo foo; 

    public MyModule(Foo foo) { 
    this.foo = foo; 
    } 

    @Override 
    public void configure() { 
    bind(Bar.class).toProvider(new Provider<Bar>() { 
     @Override public Bar get() { 
     return foo.getBar(); 
     } 
    }); 
    } 
} 

Cela me permet d'appeler paresseusement la méthode .getBar() d'un Foo exemple fourni par l'utilisateur stocké dans un champ de MyModule. Cependant, maintenant le provider has its own dependencies - d'où j'ai besoin de définir une classe non-anonyme, je spécifie un constructeur @Inject sur. Quelque chose comme:

public class MyModule extends AbstractModule { 
    private static final Foo foo; 

    public MyModule(Foo foo) { 
    this.foo = foo; 
    } 

    @Override 
    public void configure() { 
    bind(Bar.class).toProvider(BarProvider.class); 
    } 

    BarProvider implements Provider<Bar> { 
    private Baz baz; 

    @Inject BarProvider(Baz baz) { 
     this.baz = baz; 
    } 

    @Override public Bar get() { 
     return foo.getBar(baz); 
    } 
    } 
} 

Parfait! Sauf Guice doesn't like this ...

Exception dans le thread "principal" com.google.inject.CreationException: Impossible de créer injecteur, voir les erreurs suivantes:

1) Injecter dans les classes internes n'est pas pris en charge. Veuillez utiliser une classe "statique" (de niveau supérieur ou imbriqué) au lieu de com.example.MyModule $ BarProvider.

Donc, je suis dans une liaison. J'ai besoin d'accéder à la fois un champ sur le module et un type injecté à partir d'une classe Provider en même temps. Est-ce qu'il y a un moyen de faire ça?


Note: cet exemple de jouet exclut une partie de la complexité réelle - en particulier la déclaration bind() est plus impliqué, qui est la raison pour laquelle je ne peux pas définir simplement une méthode @Provides.

Répondre

0

je me rends compte que j'enferrons d'avoir Guice construire mon Provider pour moi, que je ne dois pas vraiment faire. Malgré l'exemple dans la documentation de Guice passant dans un DatabaseTransactionLogProvider.class un meilleur parallèle au premier extrait serait de construire manuellement une instance de mon Provider, et de passer à la fois l'instance Foo et une instance Provider<Baz> (provided by the module).

public class MyModule extends AbstractModule { 
    private static final Foo foo; 

    public MyModule(Foo foo) { 
    this.foo = foo; 
    } 

    @Override 
    public void configure() { 
    bind(Bar.class).toProvider(new BarProvider(foo, getProvider(Baz.class)); 
    } 

    static BarProvider implements Provider<Bar> { 
    private final Foo foo; 
    private final Provider<Baz> bazProvider; 

    BarProvider(Foo foo, Provider<Baz> bazProvider) { 
     this.foo = foo; 
     this.bazProvider = bazProvider; 
    } 

    @Override public Bar get() { 
     return foo.getBar(bazProvider.get()); 
    } 
    } 
} 
2

En partie, l'injection dans une classe interne est impossible car Guice ne peut pas créer de manière réfléchie une instance interne sans instance parent externe (l'équivalent de la syntaxe arcane outerInstance.new InnerInstance()).

Certaines options:

  • Foo injectable par gagnez de votre graphique, peut-être caché dans un PrivateModule il est donc pas exposé à votre graphique entier (si cela est important pour vous).
  • Utilisez un fournisseur interne anonyme (ou un équivalent extrait) et obtenez un Provider<Baz> à partir de la méthode getProvider(Class<T>) de AbstractModule. Vous obtiendrez une exception si vous essayez de l'appeler avant la création de l'injecteur, mais pour créer un fournisseur comme vous le faites, ce n'est probablement pas un problème.
  • Diffusez votre bind en dehors d'un problème de jouet, pour voir si @Provides est possible avec une certaine habileté.

connexes: Accessing Guice injector in its Module?

+0

Merci Jeff! Après avoir posté, j'ai réalisé que j'avais besoin de 'getProvider()'.Il me regardait droit dans les yeux, mais pour une raison quelconque, il n'a pas cliqué :) – dimo414