Кинжал: Inject @Named строки?

EDIT 2018-02-08: Пример проекта, демонстрирующий, как это сделать на https://github.com/ravn/dagger2-named-string-inject-example - Примечание: весь источник находится в одном файле !


Я смотрю, может ли кинжал заменить наш взгляд на нас (так как платформа развертывания Java работает медленно).

Я строю карту строк конфигурации во время выполнения, и я бы хотел, чтобы при необходимости кинжал.

Например, если у меня есть

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

а также

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

Я хотел бы, чтобы "ценность" была введена в стоимость.

Примеры в исходном коде не имеют никаких @Named-обычаев. Просто попытка дает следующее исключение:

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)

Как мне подойти к этому?

Ответ 1

Похоже, что у вас есть карта, и вы хотите использовать что-то, что автоматически связывает их с именованными строками. Вы не можете сделать это автоматически в кинжале, как можете в Guice, так как в Guice вы можете создать связующее свойство.

Кинжал требует знания всех ваших привязок во время компиляции, чтобы выполнить анализ, чтобы убедиться, что все привязки и зависимости выполнены

Тем не менее, вы можете сделать что-то вроде этого - это больше плита котла, но это законно.

@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");
  }
  ...
}

Это позволит использовать все привязки hte, которые нужно создать, но быть удовлетворенными значениями времени выполнения. Ключи, однако, известны во время компиляции (и должны быть, поскольку вы все равно используете @Named ("строковый литерал"). Если вы определили свои имена свойств и значения по умолчанию как постоянные строки, вы можете даже делать:

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

Это больше плиты котла, но Кинжал имеет, пытаясь устранить большую плиту котла, предпочитает анализ времени компиляции по абсолютному уменьшению числа плиток котла. Тем не менее, я предложу функцию, которая улучшит эту ситуацию, автоматически создаст модуль для свойств системы из известного списка или некоторых таких. Я думаю, что даже эта плита котла может быть уменьшена.

Ответ 2

Вы должны определить поставщика в модуле кинжала для вашего экземпляра @Named.

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

Затем вы можете ввести именованный экземпляр в свой конструктор или использовать инъекцию поля в зависимом классе.

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

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