Dagger2 с именем(@Named) Инъекция с полиморфизмом или другим объектом

#java #dependency-injection #dagger-2

#java #внедрение зависимостей #dagger-2

Вопрос:

Привет, я пытаюсь изучить именованную инъекцию в Dagger2

Вот мои классы Java, но ни один из них, похоже, не работает. Чего я хочу, так это того, что на основе аннотации @Named я хочу получить разные объекты.

 public interface Server {

    public void start();

    public void stop();

    public String request(String request);
}

public abstract class AbstractServer implements Server {

    private boolean started;

    @Override
    public void start() {
        started = true;
    }

    @Override
    public void stop() {
        if (!started) {
            throw new IllegalStateException("Server was not started");
        }
    }
}

public class AudioServer extends AbstractServer{

     @Override
    public String request(String request) {
        return "Response from Audio server: "   request;
    }

}

public class VideoServer extends AbstractServer {

    @Override
    public String request(String request) {
        return "Response from Video server: "   request;
    }
}

@Module
public class ServerModule {

    public ServerModule() {
    }

    @Provides
    @Named("audio")
    @Singleton
    AudioServer provideAudioServer() {
        return new AudioServer();
    }

    @Provides
    @Named("video")
    @Singleton
    VideoServer provideVideoServer() {
        return new VideoServer();
    }
}
  

Пожалуйста, не ServerComponent.java не выполняется компиляция

 @Singleton
@Component(modules = {ServerModule.class})
public interface ServerComponent {

    AudioServer provideAudioServer();

    VideoServer provideVideoServer();

    void inject(TestInject inject);

}

public class TestInject {

    private static final Logger logger = Logger.getLogger(TestInject.class.getSimpleName());

    @Inject
    @Named("audio")
    Server audioServer;

    public TestInject() {
//        ServerComponent component = DaggerServerComponent.builder()
//                .build();
//        component.inject(this);
    }

    public void test() {
        String serverResponse = null;
        if (audioServer != null) {
            serverResponse = audioServer.request("game.mp3");
            logger.warning(serverResponse);
        } else {
            serverResponse = "Failure";
            logger.info(serverResponse);
        }
    }

    public static void main(String[] args) {
        TestInject inject = new TestInject();
        inject.test();
    }
}
  

ОТРЕДАКТИРОВАНО, пожалуйста, смотрите Ответ в TestInject.java и ServerComponent.java

 public interface Server {

    public void start();

    public void stop();

    public String request(String request);
}

public abstract class AbstractServer implements Server {

    private boolean started;

    @Override
    public void start() {
        started = true;
    }

    @Override
    public void stop() {
        if (!started) {
            throw new IllegalStateException("Server was not started");
        }
    }
}

public class AudioServer extends AbstractServer{

     @Override
    public String request(String request) {
        return "Response from Audio server: "   request;
    }

}

public class VideoServer extends AbstractServer {

    @Override
    public String request(String request) {
        return "Response from Video server: "   request;
    }
}

@Module
public class ServerModule {

    public ServerModule() {
    }

    @Provides
    @Named("audio")
    @Singleton
    AudioServer provideAudioServer() {
        return new AudioServer();
    }

    @Provides
    @Named("video")
    @Singleton
    VideoServer provideVideoServer() {
        return new VideoServer();
    }
}
  

Пожалуйста, не ServerComponent.java не выполняется компиляция

 @Singleton
@Component(modules = {ServerModule.class})
public interface ServerComponent {

    @Named("audio")
    Server provideAudioServer();

    @Named("video")
    Server provideVideoServer();

    void inject(TestInject inject);
}

    public class TestInject {

    private static final Logger logger = Logger.getLogger(TestInject.class.getSimpleName());

    @Inject
    @Named("audio")
    Server audioServer;

    @Inject
    @Named("video")
    Server videoServer;

    public TestInject() {
        ServerComponent component = DaggerServerComponent.builder()
                .build();
        component.inject(this);
    }

    public void testAudioServer() {
        String serverResponse = null;
        if (audioServer != null) {
            serverResponse = audioServer.request("game.mp3");
            logger.warning(serverResponse);
        } else {
            serverResponse = "audio server Failure";
            logger.info(serverResponse);
        }
    }

    public void testVideoServer() {
        String serverResponse = null;
        if (videoServer != null) {
            serverResponse = videoServer.request("movie.mp4");
            logger.warning(serverResponse);
        } else {
            serverResponse = "Video server Failure";
            logger.info(serverResponse);
        }
    }

    public static void main(String[] args) {
        TestInject inject = new TestInject();
        inject.testAudioServer();
        inject.testVideoServer();
    }
}
  

Ответ №1:

Ваша основная проблема, похоже, связана с тем фактом, что вы ожидаете в классе TestInject a Server named, audio в то время как ваш провайдер возвращает AudioServer , поэтому dagger не может удовлетворить вашу зависимость.

Действительно, не забывайте, что аннотация @Named используется для различения 2 объектов одного и того же типа, другими словами, вы можете аннотировать с помощью @Named("audio") разных поставщиков, если они не возвращают один и тот же тип. Созданный объект затем будет идентифицирован по его типу и имени.

Итак, например, вот один из способов решить вашу проблему:

Класс TestInject :

 public class TestInject {
    ...

    public TestInject() {
        // Needed to inject your dependencies
        ServerComponent component = DaggerServerComponent.builder()
            .build();
        component.inject(this);
    }
    ...
}
  

Класс ServerComponent

 @Singleton
@Component(modules = ServerModule.class)
public interface ServerComponent {
    void inject(TestInject inject);
}
  

Класс ServerModule

 @Module
public class ServerModule {

    @Provides
    @Named("audio")
    @Singleton
    public Server provideAudioServer() {
        return new AudioServer();
    }

    @Provides
    @Named("video")
    @Singleton
    public Server provideVideoServer() {
        return new VideoServer();
    }
}
  

Даже с обновлением вашего вопроса ваш модуль должен быть таким, как я предлагаю, в противном случае он не будет компилироваться по той же причине, что описана ранее.

Комментарии:

1. как бы выглядел мой компонентный класс, m не понятный модуль, я допустил ошибку, должен был быть Super interface, как вы ответили, не могли бы вы, пожалуйста, рассказать, как бы выглядел component class.

2. если я не добавлю аннотацию @Named к серверному компоненту, это не будет компилятором, компонент отвечает за предоставление объектов.