John
John

Reputation: 41

Java Guice Provider

I have a small problem which I can't figure out to save my life.

Basically I need to register classes anytime dynamically using guice and then loop through them all.

Lets say this is my class to register Strategies but these strategies can be added anytime through the application running.

// Strategy registration may happen anytime, this is just an example
strategyManager.register(ExampleStrategy1.class);
strategyManager.register(ExampleStrategy2.class);

StrategyImpl class

public class StrategyImpl implements Strategy {

    @Override
    public void register(Class<? extends StrategyDispatcher> strat) {
        //Add this class into provider or create an instance for it and add it into guice but how?
    }

    @Override
    public void dispatchStrategy() {
        //Find all strategies and execute them
    }

}

I've tried using a Provider but have no idea how i'd add the registered class into the provider and retrieve them all?

@Override
protected void configure() {
    bind(Strategy.class).toProvider(StrategyProvider.class);
}

My provider class always gets the same instance

public class StrategyProvider implements Provider<StrategyDispatcher> {

    public LogManager get() {
        return new StrategyDispatcherImpl();
    }

}

The strategies that I add extend the StrategyDispatcherImpl class so i could cast them?

I need to add multiple binds to a same instance but it needs to be done dynamically and not using the bind method in configure but another way then be able to find all these strategies and execute them.

Upvotes: 2

Views: 195

Answers (1)

Michael Lloyd Lee mlk
Michael Lloyd Lee mlk

Reputation: 14661

If you truly need it to happen at "any time" during the application life cycle then Guice then I think you will need some sort of Guice-aware Factory. I.e.

public class TestStuff {
    @Test
    public void testDynamicCreation() {
        Injector injector = Guice.createInjector();
        StrategyManager manager  = injector.getInstance(StrategyManager.class);
        Hello hello = injector.getInstance(Hello.class);
        manager.doStuff();
        assertThat(hello.helloCalled, is(false));

        manager.register(Hello.class); // DYNAMIC!!
        manager.doStuff();
        assertThat(hello.helloCalled, is(true));
    }
}

interface Strategy {
    void doStuff();
}

@Singleton
class Hello implements Strategy {
    boolean helloCalled = false;
    public void doStuff() {
        helloCalled = true;
    }
}


class StrategyManager {
    private final Collection<Strategy> strategies = new ArrayList<>();
    private final StrategyFactory factory;

    @Inject
    StrategyManager(StrategyFactory factory) {
        this.factory = factory;
    }

    public void register(Class<? extends Strategy> strat) {
        strategies.add(factory.create(strat));
    }

    public void doStuff() {
        for (Strategy s : strategies) {
            s.doStuff();
        }
    }
}

class StrategyFactory {
    private final Injector injector;

    @Inject
    StrategyFactory(Injector injector) {
        this.injector = injector;
    }

    public Strategy create(Class<? extends Strategy> clazz) {
        return injector.getInstance(clazz);
    }
}

If it is not "dynamic" after the initialization phase then you are after the "multibinder" I think.

Upvotes: 2

Related Questions