I've done the same thing in my project, taking it a step further: I've
hidden the annotation implementation in an InvocationHandler and written a
simple factory that takes the annotation class and enum value and creates a
dynamic proxy for the annotation desired:
public final class AnnotationFactory {
public static <A extends Annotation,
E extends Enum<E>> A create(final Class<A> annoClass,
final E theEnum) {
// Details omitted for brevity
}
}
An AnnotationInvocationHandler class (not shown) implements the details of
the annotation specification. You wouldn't then be forced to re-implement
the annotation implementation for each new annotation class you create,
just create them programatically using the factory.
Your code could then look like this:
private void bindFoo(Class<? extends Foo> fooClass,
WhatKindOfStuff whatKindOfStuff) {
bind(Foo.class)
.annotatedWith(AnnotationFactory.create(DoesFooStuff.class,
whatKindOfStuff))
.to(fooClass);
}
This makes DoesFooStuffImpl class unnecessary.
-Russ
On Fri, Sep 7, 2012 at 9:59 AM, Fred Faber <[email protected]> wrote:
> Noticed the typos now. I started by naming "DoesFooStuff" naming as "
> FooClient", so please disregard those references.
>
> On Fri, Sep 7, 2012 at 9:57 AM, Fred Faber <[email protected]> wrote:
>
>> A pattern to mitigate the boilerplate is to use a parameterized
>> annotation:
>>
>> @Retention(RetentionPolicy.RUNTIME)
>> @BindingAnnotation
>> public @interface DoesFooStuff {
>> DoesFooStuff value();
>>
>> enum WhatKindOfStuff {
>>
>> STUFF_THAT_A_WANTS,
>>
>> STUFF_THAT_B_WANTS,
>>
>> ...
>>
>> STUFF_THAT_Z_WANTS
>>
>> }
>>
>> }
>>
>> You would then use this to annotate your Foos:
>>
>>
>> class AFoo {
>>
>> @Inject AFoo(@DoesStuffForFoo(Foo.WhatKindOfStuff.STUFF_THAT_A_WANTS) IFoo
>> foo) {
>>
>> ...
>>
>> }
>>
>> }
>>
>>
>>
>> In your module you'd define an implementation of the interface (which is
>> tricky...you need to be careful to follow the spec on the Annotation
>> javadoc):
>>
>>
>> @SuppressWarnings("ClassExplicitlyAnnotation")
>> private static class DoesFooStuffImpl implements DoesStuffForFoo {
>>
>> private final WhatKindOfStuff value;
>>
>> private DoesFooStuffImpl(WhatKindOfStuff value) {
>>
>> this.value = value;
>> }
>>
>> @Override WhatKindOfStuff String value() {
>> return value;
>> }
>>
>> @Override public Class<? extends Annotation> annotationType() {
>> return DoesStuffForFoo.class;
>> }
>>
>> @Override public String toString() {
>> return "@" + DoesStuffForFoo.class.getName() + "(value=" + value + ")";
>>
>> }
>>
>> @Override public boolean equals(Object o) {
>> return o instanceof DoesStuffForFooImpl
>>
>> && ((DoesStuffForFoo) o).value().equals(value());
>> }
>>
>> @Override public int hashCode() {
>> return (127 * "value".hashCode()) ^ value.hashCode();
>> }
>>
>> }
>>
>>
>> You could then define a helper method as syntatic sugar over the binding:
>>
>>
>> private void bindFoo(Class<? extends Foo> fooClass, WhatKindOfStuff
>> whatKindOfStuff {
>>
>> bind(Foo.class)
>> .annotatedWith(new DoesFooStuffImpl(whatKindOfStuff))
>> .to(fooClass);
>> }
>>
>> And then your bindings become:
>>
>> @Override protected void configure() {
>> bindFoo(FooThatAFooWants.class, WhatKindOfStuff.STUFF_THAT_A_WANTS);
>> bindFoo(FooThatBFooWants.class, WhatKindOfStuff.STUFF_THAT_B_WANTS);
>> ...
>> bindFoo(FooThatZFooWants.class, WhatKindOfStuff.STUFF_THAT_Z_WANTS);
>> }
>>
>>
>> Fred
>>
>> On Fri, Sep 7, 2012 at 3:02 AM, robertdup <[email protected]> wrote:
>>
>>> Yes it's right.. but this way don't satisfy me totally cause I have some
>>> XFoo classes.
>>> I will have to create many annotation (@A,@B, ..., @Z), and I must bind
>>> all of them or I will get a guice exception.
>>>
>>> bind(IFoo.class).annotatedWith.(A.class).to(DefaultFoo.class);
>>> bind(IFoo.class).annotatedWith.(B.class).to(DefaultFoo.class);
>>> [...]
>>> bind(IFoo.class).annotatedWith.(Y.class).to(DefaultFoo.class);
>>> bind(IFoo.class).annotatedWith.(Z.class).to(DefaultFoo.class);
>>>
>>> In my case, I just have to override a couple of binding and let the
>>> other on the default implementation (DefaultFoo.class)
>>> bind(IFoo.class).annotatedWith.(E.class).to(MyEFoo.class);
>>> bind(IFoo.class).annotatedWith.(K.class).to(MyKFoo.class);
>>>
>>> Otherwise, PrivateModule looks too "heavy" to implement in my case..
>>>
>>>
>>> - Well, Is there an other way that could be less verbose ?
>>>
>>>
>>> Best regards;
>>>
>>>
>>> On Friday, September 7, 2012 3:59:12 AM UTC+2, Fred Faber wrote:
>>>
>>>> Strictly speaking, the robot legs problem describes a scenario where
>>>> the types of your object chain are identical. In your case, you wouldn't
>>>> have AFoo and BFoo, but just Foo. It's a luxury of sorts to have AFoo and
>>>> BFoo because you _can_ use a binding annotation on the constructor of each.
>>>> That is the solution I would prefer for its clarity in how AFoo and BFoo
>>>> are being configured:
>>>>
>>>> class AFoo {
>>>> @Inject AFoo(@DoesStuffRelatedToA IFoo ifoo) { ... }
>>>> }
>>>>
>>>> class BFoo {
>>>> @Inject BFoo(@DoesStuffRelatedToB IFoo ifoo) { ... }
>>>> }
>>>>
>>>> Here, grepping through the code directly for DoesStuffRelatedToA would
>>>> lead me to the binding for IFoo in context of AFoo, and that's a little bit
>>>> of a win for code maintenance.
>>>>
>>>> Fred
>>>>
>>>> On Thu, Sep 6, 2012 at 12:51 PM, robertdup <[email protected]> wrote:
>>>>
>>>>> Thanks for your reply.
>>>>>
>>>>> Do you know if it's a common uses to have more than 20 privates
>>>>> modules ?
>>>>>
>>>>>
>>>>>
>>>>> On Thursday, September 6, 2012 4:00:35 PM UTC+2, Thomas Broyer wrote:
>>>>>>
>>>>>> This is known as the "robot legs" problem, see
>>>>>> http://code.google.com/p/**g**oogle-guice/wiki/**FrequentlyAsk**
>>>>>> edQuestions#How_**do_I_build_**two_similar_but_**slightly_**
>>>>>> different_trees_of_**objec<http://code.google.com/p/google-guice/wiki/FrequentlyAskedQuestions#How_do_I_build_two_similar_but_slightly_different_trees_of_objec>
>>>>>>
>>>>>> On Thursday, September 6, 2012 9:14:24 AM UTC+2, robertdup wrote:
>>>>>>>
>>>>>>> Hello there,
>>>>>>>
>>>>>>> I trying to implement default binding on my module without any
>>>>>>> success...
>>>>>>>
>>>>>>> Here is what I would like to do (*my dream*) :
>>>>>>>
>>>>>>> class AFoo
>>>>>>>> {
>>>>>>>> @Inject AFoo( IFoo foo ){}
>>>>>>>> }
>>>>>>>>
>>>>>>>> class BFoo
>>>>>>>> {
>>>>>>>> @Inject BFoo( IFoo foo ){}
>>>>>>>> }
>>>>>>>>
>>>>>>>>
>>>>>>>> bind(IFoo.class).to(**DefaultFoo**.class);
>>>>>>>> bind(IFoo.class).to(OtherFoo.**c**lass)*.on(BFoo.class)*;
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> I know that I could solve this problem using annotation like this :
>>>>>>>
>>>>>>> class AFoo
>>>>>>>> {
>>>>>>>> @Inject AFoo( @A IFoo foo ){}
>>>>>>>> }
>>>>>>>>
>>>>>>>> class BFoo
>>>>>>>> {
>>>>>>>> @Inject BFoo( @B IFoo foo ){}
>>>>>>>> }
>>>>>>>>
>>>>>>>>
>>>>>>>> bind(IFoo.class).**annotatedWith**(A.class).to(**DefaultFoo.class)*
>>>>>>>> *;
>>>>>>>> bind(IFoo.class).**annotatedWith**(B.class).to(**OtherFoo.class);
>>>>>>>>
>>>>>>>
>>>>>>> But this way is too boring and dirty.. (because I have to add
>>>>>>> annotation/binding definition for each one)
>>>>>>>
>>>>>>>
>>>>>>> - *Are there some others ways to solve Default binding "problem"
>>>>>>> ?*
>>>>>>>
>>>>>>> Thanks in advance; Best regards
>>>>>>>
>>>>>> --
>>>>> You received this message because you are subscribed to the Google
>>>>> Groups "google-guice" group.
>>>>> To view this discussion on the web visit https://groups.google.com/d/*
>>>>> *msg/google-guice/-/**bqRh1CKDwsEJ<https://groups.google.com/d/msg/google-guice/-/bqRh1CKDwsEJ>
>>>>> .
>>>>>
>>>>> To post to this group, send email to [email protected].
>>>>> To unsubscribe from this group, send email to google-guice...@**
>>>>> googlegroups.com.
>>>>>
>>>>> For more options, visit this group at http://groups.google.com/**
>>>>> group/google-guice?hl=en<http://groups.google.com/group/google-guice?hl=en>
>>>>> .
>>>>>
>>>>
>>>>
>>
> --
> You received this message because you are subscribed to the Google Groups
> "google-guice" group.
> To post to this group, send email to [email protected].
> To unsubscribe from this group, send email to
> [email protected].
> For more options, visit this group at
> http://groups.google.com/group/google-guice?hl=en.
>
--
Gambling Problem? Call 1-800-Gambler
--
You received this message because you are subscribed to the Google Groups
"google-guice" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/google-guice?hl=en.