guicerobot-legs-problem

guice: multiple implementations, different object graphs


How do you do the following in guice?

There is class XmlSerializer that depends on an interface XmlFormatter. There are 2 implementations of XmlFormatter: CompactXmlFormatter and PrettyXmlFormatter.

Another class MyApplication depends on 2 instances of XmlSerializer. One instance should be configured with a CompactXmlFormatter and the other PrettyXmlFormatter

public class XmlSerializer {
    public XmlSerializer(XmlFormatter formatter) {
       ...
    }
}

public interface XmlFormatter {
    ...
}

public class CompactXmlFormatter implements XmlFormatter {
    ...
}

public class PrettyXmlFormatter implements XmlFormatter {
    ...
}

public class MyApplication {
    public MyApplication(XmlSerializer compactSerializer, XmlSerializer prettySerializer) {
        ...
    }
}

How do you construct such a graph?

I know that, once you have the 2 XmlSerializer instances, injecting them to MyApplication requires annotations in the parameters of the MyApplication constructor.

I am more interested in how do you bind XmlFormatter to both CompactXmlFormatter and PrettyXmlFormatter.


Solution

  • Use binding annotations to differentiate each XmlFormatter.

    In your Module:

    bind(XmlFormatter.class).aannotatedWith(Pretty.class)
        .to(PrettyXmlFormatter.class);
    bind(XmlFormatter.class).aannotatedWith(Compact.class)
        .to(CompactXmlFormatter.class);
    

    And:

    @Inject public MyApplication(
        @Compact XmlSerializer compactSerializer, 
        @Pretty XmlSerializer prettySerializer) {
        ...
    

    Of course you'll have to define @Pretty and @Compact annotations:

    @BindingAnnotation 
    @Target({ FIELD, PARAMETER, METHOD }) 
    @Retention(RUNTIME) 
    public @interface Pretty {}
    
    @BindingAnnotation 
    @Target({ FIELD, PARAMETER, METHOD }) 
    @Retention(RUNTIME) 
    public @interface Compact {}