Я изучаю Даггер. Я бывший пользователь Spring. Одна из вещей, которую я заметил, это то, что мне нужно аннотировать каждый компонент с помощью @IntoSet, чтобы добавить компоненты определенного типа в коллекцию. В Spring я бы прямо объявил, например, Set<MyBeanClass> в качестве параметра в методе или конструкторе с автоматическим подключением, и фреймворк сам все выяснит (конечно, «фреймворк, который все сделает за вас», не всегда является преимуществом).
Однако @IntoSet иногда что-то ломает. Вот MRE:
package myown;
import dagger.Component;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.Set;
@Component(modules = {PersonModule.class})
@Singleton
public interface PersonComponent {
Person getJane();
}
package myown;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoSet;
import javax.inject.Singleton;
@Module(includes = PetModule.class)
public class PersonModule {
@IntoSet
@Singleton
@Provides
public Person jane(Pet pet) {
return new PetOwner("Jane", pet);
}
}
package myown;
import dagger.Module;
import dagger.Provides;
import javax.inject.Singleton;
@Module
public class PetModule {
@Provides
@Singleton
Pet getPet() {
return new Pet("Puffy");
}
}
package myown;
public class Person {
private final String name;
public Person(String name) {
this.name = name;
}
}
package myown;
public class PetOwner extends Person {
private final Pet pet;
public PetOwner(String name, Pet pet) {
super(name);
this.pet = pet;
}
}
package myown;
public class Pet {
private final String name;
public Pet(String name) {
this.name = name;
}
}
Попробуйте построить его и вы получите:
java: [Dagger/MissingBinding] myown.Person cannot be provided without an @Inject constructor or an @Provides-annotated method.
myown.Person is provided at
myown.PersonComponent.getJane()
Однако если вы закомментируете @IntoSet и попытаетесь пересобрать, все будет в порядке.
Чтобы внести ясность, я хочу, чтобы jane можно было вводить непосредственно и как часть инъекции Set из всех Person (представьте, что есть jack, john и т. д., также помеченные @IntoSet)
Почему это происходит и есть ли решение/обходной путь?




Когда вы предоставляете @IntoSet, он будет только в вашем наборе. Вы не можете напрямую ввести «Джейн»
Если вы хотите внедрить Джейн конкретно, вы можете предоставить Джейн именованную аннотацию или подтип, а затем привязать или предоставить их снова с помощью @IntoSet.
@Module(includes = PetModule.class)
public class PersonModule {
@Singleton
@Provides
@Named("Jane")
public Person jane(Pet pet) {
return new PetOwner("Jane", pet);
@Provides
@IntoSet
public Person janeIntoSet(@Named("Jane") jane: Person) {
return jane;
}
}
Есть несколько способов добиться этого. См. https://dagger.dev/dev-guide/multibindings.html.
Разница в Spring заключается в том, что он определяет это во время выполнения, в то время как все в dagger генерируется во время компиляции. Так что здесь не происходит никаких догадок, кастингов или размышлений. Все должно быть ясно во время компиляции.
Спасибо! Я заметил, что Даггеру требуется
@Named, даже если у меня есть толькоjane(иjaneIntoSet, который тоже является Джейн).Person getJane()в интерфейсе@Componentне будет работать, если я специально не упомяну, что разыскивается Джейн.