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 :
|
publicclassModuleGuiceextendsAbstractModule{
@Overrideprotectedvoidconfigure(){
Parentbinder
.newBinder(binder(),UserService.class)
.setBinding()
.to(UserFrameworkService.class);
}
}
|
Then, in the plugins service overriding, I would have something like :
|
publicclassUserWsServiceimplementsUserService{
privatefinalUserServiceparent;
privatefinalUserApiuserApi;
@InjectpublicUserWsService(@ParentUserServiceparent,UserApiuserApi){
this.parent =parent;
this.userApi =userApi;
}
@OverridepublicList<User>users(){
returnImmutableList.builder().addAll(parent.users()).addAll(ws.users()).build();
}
}
|
And eventually, in the Application, I would just have to do :
|
Injectorinjector
=Guice.createInjector(newFrameworkModule(),newWebServiceModule(),newGroupModule());
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] <javascript:>>:
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
<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]
<mailto:[email protected]>.
To post to this group, send email to [email protected]
<mailto:[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/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/54D32322.8020602%40gmx.ch.
For more options, visit https://groups.google.com/d/optout.