Yes exactly: I want a chain like behavior where the order of the modules in
the createInjector method determines the order in the chain.
However, I think the Multibinder Set binder does preserve the ordering.
Indeed, Multibinder is using an ImmutableSet which preserves the order from
construction time :
https://code.google.com/p/guava-libraries/wiki/ImmutableCollectionsExplained
But ultimately, I also want to be able to create the Framework without
thinking about how plugins will alter the base functionalities.
The ChainedUserService example have one main problem for me : code have to
be added in the Framework to enable plugins to filter the result. So if a
new plugin does not want to filter the result, but merge the result with
another result (from a web-service for instance), the Framework will have
to be modified in order to build the new plugin.
Looking at the code of the multibindings extension, it seems it isn't to
hard to extend Guice. I will try to implement a POC of my use case and I
will come back here to talk about it.
Thank you all for your answers, you enable me to understand my need better !
On Thursday, February 5, 2015 at 9:00:39 AM UTC+1, scl wrote:
>
> So what you want is a chain like behavior where the order of the modules
> in the createInjector method determines the order in the chain.
> I don't think this is easily possible with the current guice extensions.
> Multibinder offers a Set and a Map binder. Neither of them preserves the
> ordering.
>
> You could make a hacky thing where you use Integer as key for the
> MapBinder. During injector creation you could have a static counter which
> will map each binding to a unique increasing value (0, 1, 2, ...). In the
> application you can then iterate over the number of elements in the Map and
> retrieve them by their key.
>
> Something like this (sorry pseudo code, not my dev machine...):
>
> ----
>
> private static int userServiceCounter;
>
> public static addBindingToUserServiceChain(Binder binder, Class<? extends
> UserServiceFilter> implementation) {
> // make the binding here
> }
>
> ----
>
> class ChainedUserService implements UserService {
>
> private final CoreUserService coreService
> private final Map<Integer, UserServiceFilter> filterServices;
>
> @Override
> public List<User> getUsers() {
> final int n = services.size();
> List<User> result = coreService.getUsers();
>
> for (int i = 0; i < n; i++) {
> final UserServiceFilter filter = filterServices.get(i);
> result = filter.getUser(result);
> }
> }
>
> ----
>
> Core would then bind ChainedUserService to UserService.
>
>
>
>
> On 02/04/2015 11:34 PM, Aurélien wrote:
>
> Thank you for your responses.
>
> The OptionalBinder lead me to what I want : a plugin-type architecture.
> I could not reference a parent implementation with OptionalBinder.
> However, the Multibinder enable to add multiple implementations and to
> reference all these implementations.
>
> Although the Multibinder pattern is good, it means the Framework
> implementation needs to guess most of the sub plugins uses.
>
> Here is an example of what I would like to do :
> 1/ The Framework defines a method to fetch the application users :
> List<User> users();
> The base implementation connect to a database and fetch all the users.
>
> 2/ The plugin web-service fetch users on an API on the Internet and add
> them to the default implementation :
> list(parent.users()).addAll(ws.users());
>
> 3/ The plugin group filter users who are in the same group as the current
> user : parent.users().filter(user -> user.group() == currentUser.group());
>
> Then in the application, I will be able to :
> - use the framework only : users() returns all the users in the database,
> - use the group plugin : users() returns all the users in the database who
> are in the same group as the current user
> - use the web-service plugin : users() returns all the users in the
> database plus all the users provided by some web-service
> - use both the group plugin and the web-service plugin : users() returns
> database users and web-service users but filtered by the group
>
> This would be awesome because in the Framework I wouldn't have to think
> how plugins will change the default features.
>
> To achieve this, using the MultiBindings Guice extension style, I would
> have framework and plugins declare modules this way :
> public class ModuleGuice extends AbstractModule {
> @Override protected void configure() {
> Parentbinder
> .newBinder(binder(), UserService.class)
> .setBinding()
> .to(UserFrameworkService.class);
> }
> }
>
> Then, in the plugins service overriding, I would have something like :
> public class UserWsService implements UserService {
>
> private final UserService parent;
> private final UserApi userApi;
>
> @Inject public UserWsService(@Parent UserService parent, UserApi
> userApi) {
> this.parent = parent;
> this.userApi = userApi;
> }
>
> @Override public List<User> users() {
> return ImmutableList.builder().addAll(parent.users()).addAll(ws.
> users()).build();
> }
>
> }
>
> And eventually, in the Application, I would just have to do :
> Injector injector = Guice.createInjector(new FrameworkModule(), new
> WebServiceModule(), new GroupModule());
> injector.getInstance(UserService.class).users(); // database + ws users
> filtered by group
>
> Do I have to look in ExtendingGuice documentation
> <https://github.com/google/guice/wiki/ExtendingGuice> to implement this
> or another class in the MultiBindings Guice extension might do the job (or
> elsewhere!) ?
>
> Thank you for your help!
> Aurélien
>
> On Wednesday, February 4, 2015 at 10:42:46 PM UTC+1, scl wrote:
>>
>> One thing that will not work is injecting A into either ASub or
>> AOtherSub. Because this will create an endless loop sinc A is bound to ASub
>> resp. AOtherSub.
>> You need to be more specific and either request ACore or introduce a name
>> for the parent so you could inject (@Parent A)
>>
>> Am 4. Februar 2015 16:59:09 MEZ, schrieb Joshua Moore-Oliva <
>> [email protected]>:
>>>
>>> If I am understanding your use case correctly, it sounds like you may be
>>> interested in using the OptionalBinder that is new in guice4. It would
>>> allow you to set up a default binding (setDefault) in core, and then
>>> override that in a sub (setBinding).
>>>
>>> The javadoc is fairly thorough and has some examples here:
>>>
>>>
>>> http://google.github.io/guice/api-docs/latest/javadoc/com/google/inject/multibindings/OptionalBinder.html
>>>
>>>
>>>
>>> On Tuesday, February 3, 2015 at 3:36:28 PM UTC-7, Aurélien wrote:
>>>>
>>>> Hi,
>>>>
>>>> I have a peculiar use case:
>>>> - I have 3 libraries, Core, Sub and OtherSub
>>>> - Sub and OtherSub do not know anything about each other, but they know
>>>> the existence of Core
>>>> - Sub and OtherSub override the same functionality in Core
>>>> - In a project, I want to combine Sub and OtherSub.
>>>>
>>>> It does not work, but here is how I wanted to implement this pattern
>>>> with Guice:
>>>> - in the Core library:
>>>> o bind(A.class).to(ACore.class)
>>>> o class ACore implements A {
>>>> @Override public String a() { "a"; }
>>>> }
>>>> - in the Sub library:
>>>> o bind(A.class).to(ASub.class)
>>>> o class ASub implements A {
>>>> private final A parent; // instance of ACore or AOtherSub
>>>> @Inject ASub(A parent) { this.a = parent; }
>>>> @Override public String a() { parent.a() + " overriden"; }
>>>> }
>>>> - in the OtherSub library:
>>>> o bind(A.class).to(AOtherSub.class)
>>>> o class AOtherSub implements A {
>>>> private final A parent; // instance of ACore or ASub
>>>> @Inject ASub(A parent) { this.a = parent; }
>>>> @Override public String a() { parent.a() + " !"; }
>>>> }
>>>>
>>>> then in the projet using this set of libraries, I would have been able
>>>> to do:
>>>> - Guice.createInjector(Modules.override(new ModuleCore()).with(new
>>>> AOtherSub())).getInstance(A.class).a() // returns "a !"
>>>> - Guice.createInjector(Modules.override(Modules.override(new
>>>> ModuleCore()).with(new ASub())).with(new
>>>> AOtherSub())).getInstance(A.class).a() // returns "a overriden !"
>>>> - Guice.createInjector(Modules.override(Modules.override(new
>>>> ModuleCore()).with(new AOtherSub())).with(new
>>>> ASub())).getInstance(A.class).a() // returns "a ! overriden"
>>>>
>>>> In this implementation, this throws a StackOverflowError because in
>>>> ASub or in AOtherSub the instance creation falls in an infinite loop.
>>>>
>>>> Is there a way of doing something like that with Guice ?
>>>> Else do you have any insight on how I should implement this use case ?
>>>>
>>>> Cheers,
>>>> Aurélien
>>>>
>>> --
> You received this message because you are subscribed to the Google Groups
> "google-guice" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to [email protected] <javascript:>.
> To post to this group, send email to [email protected]
> <javascript:>.
> Visit this group at http://groups.google.com/group/google-guice.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/google-guice/f348749b-8b33-4d81-a8c4-c5d1256805e7%40googlegroups.com
>
> <https://groups.google.com/d/msgid/google-guice/f348749b-8b33-4d81-a8c4-c5d1256805e7%40googlegroups.com?utm_medium=email&utm_source=footer>
> .
> For more options, visit https://groups.google.com/d/optout.
>
>
>
--
You received this message because you are subscribed to the Google Groups
"google-guice" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/google-guice.
To view this discussion on the web visit
https://groups.google.com/d/msgid/google-guice/e544b9cb-51fa-482e-9ba6-2ba27a153c32%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.