Dagger 2 - Предоставленный объект нуждается в экземпляре из целевого метода - PullRequest
0 голосов
/ 21 марта 2019

Мне нужно предоставить TimeStamp до deserialize метод JsonDeserializer в кинжале 2.

@Singleton
@Provides
public JsonDeserializer provideJsonDeserializer() {
        return new JsonDeserializer() {
            public Timestamp deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                return new Timestamp(json.getAsJsonPrimitive().getAsLong());
            }
        };
    }

но для этого объекта требуется JsonElement объект из JsonDeserializer. Как я могу передать этот объект моему методу provideTimestamp.

@Singleton
@Provides
public Timestamp provideTimestamp() {


}

Или я просто не должен вводить Timestamp через кинжал, если это так, кто-то может объяснить, почему, это может помочь мне узнать больше о кинжале 2.

1 Ответ

0 голосов
/ 23 марта 2019

Правильно, как у вас в первом примере кода, и как у меня это получилось: вы должны звонить new Timestamp(...), а не откладывать Dagger.

Различие, которое вы должны рисовать: injectables vs newables : Какие объекты в вашем графике следует вводить и какие объекты следует создавать с помощью new? Может быть соблазнительно думать, что каждый вызов new плох, потому что он снижает гибкость, но реальность такова, что это скорее суждение:

  • Если вы когда-нибудь захотите изменить или заменить реализацию, даже используя тестовые двойники или макеты в тестах, тогда ваш объект должен быть инъецируемый . Это особенно верно для недетерминированных или дорогих объектов, потому что вы, вероятно, хотите, чтобы ваши тесты были быстрыми и детерминированными.
  • Если реализации являются «объектами значений», которые делают немного больше, чем носят структурированные данные, то они вряд ли будут заменены и, вероятно, newable .
  • Если реализации имеют мало зависимостей и их легко создать, они могут быть newable . Если реализации принимают множество сервисов в качестве параметров конструктора (в отличие от многих значений данных), то они, вероятно, должны быть injectable ; это было бы хорошей причиной для использования подделок или насмешек в ваших тестах.

См. Также: «Новым» или не «новым»… , автор Miško Hevery


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

В вашем случае у вас есть дополнительная складка: ваша новая временная метка будет меняться в зависимости от объекта json, который вы передаете, а объект json будет меняться настолько, что вряд ли вы захотите положить его в свой график кинжала. Это означает, что если вы захотели продолжить внедрение, а не вводить метку времени, вам, вероятно, нужно внедрить TimestampFactory, которая может быть ссылкой на конструктор , Автозаводом -созданная реализация или любая другая реализация:

interface TimestampFactory {
  Timestamp create(long value);
}

Это кажется чрезмерным, но давайте представим , вместо этого вам понадобится Timestamp2, который также записывает текущее время дня и, следовательно, может затруднить тестирование. В этом случае вы можете ввести свою фабрику временных меток :

@Singleton
@Provides
public JsonDeserializer provideJsonDeserializer(Timestamp2Factory tsFactory) {
  return new JsonDeserializer() {
    public Timestamp2 deserialize(JsonElement json, Type typeOfT,
        JsonDeserializationContext context) throws JsonParseException {
      return tsFactory.create(json.getAsJsonPrimitive().getAsLong());
    }
  };
}

@Reusable
@Provides
public Timestamp2Factory provideTimestamp2Factory() {
  // Merge in other parameters and dependencies if needed,
  // but Timestamp2 only needs one value that create(long) supplies.
  return Timestamp2::new;
  // or, pre-Java-8:
  return new Timestamp2Factory() {
    @Override public Timestamp2 create(long time) {
      return new Timestamp2(time);
    }
  }
}

Это позволит вам вызвать provideJsonDeserializer в ваших тестах и ​​передать выбранную вами TimestampFactory, например, такую, которая использует поддельное системное время вместо реального. Это позволит сделать ваши тесты намного безопаснее и более детерминированными.

Однако, поскольку вам нужна быстрая метка времени объекта с определенным значением, которая не имеет внешних зависимостей, таких как службы RPC, доступ к файловой системе или фактическое системное время, оставьте вызов new Timestamp таким же, как в вашем вопросе.

...