Maybe filter was not the best choice of a name. So don't let yourself be tricket by this. At the end the interface method is:
List<User> getUsers(List<User> users); And the concrete implementation is absolutely free to add, remove or replace users from the list. Am 7. Februar 2015 18:10:14 MEZ, schrieb "Aurélien" <[email protected]>: >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. -- 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/82C9FD6C-39D4-48FA-8ED1-561D58849DFE%40gmx.ch. For more options, visit https://groups.google.com/d/optout.
