Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dagger2 Named(@Named) Injection with polymorphism or different object

Hi i am trying to study named injection in Dagger2

Here are my Java classes but none of them seems to be working. What i want is that based on @Named annotation i wish to get different objects.

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();
    }
}

Please not ServerComponent.java is not compiling

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

EDITED Please see answer in TestInject.java and 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();
    }
}

Please not ServerComponent.java is not compiling

@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();
    }
}
like image 207
silentsudo Avatar asked Nov 20 '25 08:11

silentsudo


1 Answers

Your main problem seems to be related to the fact that you expect in the class TestInject a Server named audio while your provider returns AudioServer so dagger cannot satisfy your dependency.

Indeed don't forget that the annotation @Named is used to distinguish 2 objects of the same type, in other words you can annotate with @Named("audio") different providers as long as they don't return the same type. The object produced will then be identified by its type and its name.

So for example here is one way to fix you problem:

The class TestInject:

public class TestInject {
    ...

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

The class ServerComponent

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

The class 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();
    }
}

Even with your question update, your module should be what I propose abose otherwise it won't compile for the same reason described previously.

like image 160
Nicolas Filotto Avatar answered Nov 21 '25 22:11

Nicolas Filotto



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!