web-dev-qa-db-fra.com

Dagger: Injecter des chaînes @Named?

[~ # ~] edit [~ # ~] 2018-02-08: Exemple de projet montrant comment faire cela à https://github.com/ravn/dagger2-named-string-inject-example - Remarque: la source entière est dans un seul fichier !


Je cherche à savoir si le poignard peut remplacer guice pour nous (car notre déploiement Java plate-forme est lent).

Je construis une carte des chaînes de configuration au moment de l'exécution, que j'aimerais que la dague injecte au besoin.

Par exemple. Si j'ai

Java.util.Map<String, String> map = new Java.util.TreeMap<String, String>();
map.put("key", "value");

et

@Inject
Thermosiphon(Heater heater, @Named("key") String value) {
    this.heater = heater;
    System.out.println("value =" + value);
}

J'aimerais avoir de la "valeur" injectée en valeur.

Les exemples du code source n'ont aucune utilisation @Named. Le simple fait d'essayer donne l'exception suivante:

Exception in thread "main" Java.lang.IllegalStateException: Errors creating object graph:
  No binding for @javax.inject.Named(value=key)/Java.lang.String required by class bar.Thermosiphon
    at dagger.internal.ThrowingErrorHandler.handleErrors(ThrowingErrorHandler.Java:34)
    at dagger.internal.Linker.linkRequested(Linker.Java:146)
    at dagger.ObjectGraph$DaggerObjectGraph.getInjectableTypeBinding(ObjectGraph.Java:288)
    at dagger.ObjectGraph$DaggerObjectGraph.get(ObjectGraph.Java:249)
    at app.CoffeeApp.main(CoffeeApp.Java:20)

Comment dois-je aborder cela?

21

Il semble que vous ayez une carte et que vous souhaitiez utiliser quelque chose qui les lie automatiquement à des chaînes nommées. Vous ne pouvez pas le faire aussi automatiquement dans Dagger que dans Guice, car dans Guice, vous pouvez créer un classeur de propriétés.

Dagger nécessite la connaissance de toutes vos liaisons au moment de la compilation, afin de faire l'analyse pour s'assurer que toutes les liaisons et dépendances sont satisfaites

Cela dit, vous pourriez faire quelque chose comme ça - c'est plus une plaque chauffante, mais c'est légitime.

@Module(library = true)
public class PropertiesModule {
  public final Properties props;

  PropertiesModule(Properties props) {
    this.props = props;
  }

  @Provides @Named("property.one") String providePropertyOne() {
    props.getProperty("property.one", "some default");
  }

  @Provides @Named("property.two") String providePropertyTwo() {
    props.getProperty("property.two", "some other default");
  }
  ...
}

Cela permettra de créer toutes les liaisons hte dont vous avez besoin, mais d'être satisfaites à partir des valeurs d'exécution. Les clés, cependant, sont connues au moment de la compilation (et doivent l'être, puisque vous utilisez de toute façon @Named ("string literal") dans votre code. Heck, si vous avez défini vos noms de propriété et vos valeurs par défaut comme des chaînes constantes, vous pouvez même faire:

  @Provides @Named(PROPERTY_NAME_CONSTANT) String a() {
    props.getProperty(PROPERTY_NAME_CONSTANT, PROPERTY_NAME_CONSTANT_DEFAULT);
  }

Il s'agit davantage d'une plaque de chaudière, mais Dagger, tout en essayant d'éliminer une grande partie de la plaque de chaudière, a préféré l'analyse du temps de compilation à la réduction absolue de la plaque de chaudière. Cela dit, je vais proposer une fonctionnalité qui améliorera cette situation, en générant automatiquement un module pour les propriétés du système à partir d'une liste connue, ou une autre. Je pense que même cette plaque chauffante peut être réduite.

19
Christian Gruber

Vous devez définir un fournisseur dans le module dagger pour votre instance @Named.

@Provides @Named("foo") String provideFoo()
{
    return "foo string";
}

Ensuite, vous pouvez injecter l'instance nommée dans votre constructeur ou en utilisant l'injection de champ dans votre classe dépendante.

public class Thermosiphon
{
    @Inject @Named("foo") String fooString;

    @Inject public Thermosiphon(Heater heater)
    {
        System.out.println("value of fooString is " + fooString);
    }
}
16
jfrey