Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google Guice Autowiring for Factory

Please explain the correct way to auto-wire using Google-Guice in the following scenario where factory is used.I am using XML factory for XSLT processing.

StringWriter strWriter = new StringWriter();
System.setProperty("javax.xml.transform.TransformerFactory",
                "net.sf.saxon.TransformerFactoryImpl");
TransformerFactory xmlTransformerFactory = TransformerFactory.newInstance();
CustomUriResolver out = new CustomUriResolver(new HashMap<String, StringWriter>());
xmlTransformerFactory.setAttribute("http://saxon.sf.net/feature/outputURIResolver", out );
Transformer xmlTransfomer = xmlTransformerFactory.newTransformer(new StreamSource("src/main/resources/test.xslt"));
xmlTransfomer.transform(new StreamSource(new StringReader(xml)), new StreamResult(strWriter));
System.out.println(out.getResults().size());
for( Map.Entry resultEntry : out.getResults().entrySet() ){
    System.out.println(resultEntry.getValue());
};

Should I have to auto-wire Transformer factory , which requires custom URI resolver.Also this piece of code is part of API which will keep receiving requests and process it.But then it has to call newTransformer() for every request it receives.

like image 666
Renganathan V Avatar asked Oct 18 '22 01:10

Renganathan V


1 Answers

The way to do this is to simply let Guice handle the dependency for you. How you create your dependency is up to you - guice doesn't care (unless you must use interceptors where guice needs to create the dependency for you.

For this case, I would use a provider to inject my dependencies. Essentially you'll want to extract all creation logic out, so that it is executed once to store your transformer and then inject that transformer everywhere. The reason I am using a provider is so that I can inject more dependencies into it (you can do the same by annotating a method as provider I believe).

See this example:

public class TransformerProvider implements Provider<Transformer> {

        @Inject
        @Named("output.uri.resolver")
        String outputUriResolver;

        @Inject
        @Named("xslt.location")
        String xsltLocation;

        Transformer instance = null;

        @Override
        public Transformer get() {
            if(instance == null) {
                try {
                    instance = create();
                } catch (TransformerConfigurationException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            return instance;
        }

        private Transformer create() throws TransformerConfigurationException {
            System.setProperty("javax.xml.transform.TransformerFactory",
                            "net.sf.saxon.TransformerFactoryImpl");
            TransformerFactory xmlTransformerFactory = TransformerFactory.newInstance();
            CustomUriResolver out = new CustomUriResolver(new HashMap<String, StringWriter>());
            xmlTransformerFactory.setAttribute(outputUriResolver, out );
            return xmlTransformerFactory.newTransformer(new StreamSource(xsltLocation));
        }
    }

This class acts as a provider for your Transformer. It initiates it the first time it is required and will store the instance for you. Alternatively you can construct it in the constructor as well.

I am injecting the 2 common properties (uri resolver and the location of the xslt). The latter at the very least might make it easier to test your application (just inject a different xslt into the provider to test it?).

Then I need to bind it in any module so that Guice knows about it and can use it:

Injector i = Guice.createInjector(new AbstractModule() {
            @Override
            protected void configure() {
                bind(Transformer.class).toProvider(TransformerProvider.class).in(Singleton.class); // bind factory
            }
        });

I am binding the Type to its provider in a singleton. That means that only 1 instance of that provider will be used throughout your application.

Alternatively you can do either of those 2 options as well:

  1. Bind the transformer in your module. Essentially put all the creation code into a module in guice and then bind the created Transformer as a singleton.

  2. Create a provider method. This is simply an annotated method in the Guice Module that will return a Transformer for you.

All of them essentially solve the same issue: Have an instance of the XMLTransformer ready in your application for injection.

I hope that's what you're looking for,

Artur

like image 158
pandaadb Avatar answered Oct 22 '22 00:10

pandaadb