Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

auto scan for guice

I have never used guice before, and I wanted to try it out on an example project with jersey based JAX-RS API backed by a service-bean. I followed this guide: http://randomizedsort.blogspot.de/2011/05/using-guice-ified-jersey-in-embedded.html and was able to bring it to work. My setup is very simple, a JAX-RS resource is invoked via Guice and has a field that is annotated @Inject and injected by Guice:

@Path("configuration")
@Produces(MediaType.APPLICATION_JSON)
@Singleton
public class ConfigurationResource {

    @Inject
    private ConfigurationService configurationService;

So far so good, everything works like it should, besides following: I am using GuiceServletContextListener for setting things up and have to name each component explicitly:

@WebListener
public class GuiceInitializer extends GuiceServletContextListener{
    @Override
    protected Injector getInjector() {
        return Guice.createInjector(new JerseyServletModule() {
            @Override
            protected void configureServlets() {
                //resources
                bind(ConfigurationResource.class);

                //services
                bind(ConfigurationService.class).to(ConfigurationServiceImpl.class);

                // Route all requests through GuiceContainer
                serve("/management/*").with(GuiceContainer.class);
            }
        });
    }
}

I find it pretty inconvenient to explicitly name all dependencies. I have worked with standalone jersey before and it's perfectly capable of auto-scanning for resources in defined packages. Also Spring and CDI are capable of mapping implementation to interfaces without need to explicitly name them.

Now the question part:

  • is there any autoscan extension/setting for guice? I found some on the internet, but it's hard to tell which of them are still useable and uptodate.

  • is there any other possibility to make configuration of implementations and resources more convenient?

thanks in advance. Leon

like image 937
Leon Avatar asked May 18 '15 21:05

Leon


People also ask

What does Guice Createinjector do?

Builds the graphs of objects that make up your application. The injector tracks the dependencies for each type and uses bindings to inject them. This is the core of Guice, although you rarely interact with it directly.

What does @provides do in Java?

@Provides Methods When you need code to create an object, use an @Provides method. The method must be defined within a module, and it must have an @Provides annotation. The method's return type is the bound type. Whenever the injector needs an instance of that type, it will invoke the method.

What is @named annotation in Guice?

4.1. We can use the optional @Named annotation as a qualifier to implement targeted injection based on the name.

Which is better Guice or Spring?

Spring allows you to omit the @Autowired annotation when there's only one constructor. Guice allows binding to a Provider, as well as injecting a Provider of your class, even when your class has no Provider binding.


1 Answers

I do not think Guice has built in support for someting like the component-scan of Spring framework. However, it is not difficult to simulate this feature in Guice.

You simply need to write a helper module like the following

import com.google.inject.AbstractModule;
import org.reflections.Reflections;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * To use this helper module, call install(new ComponentScanModule("com.foo", Named.class); in the configure method of 
 * another module class.
 */
public final class ComponentScanModule extends AbstractModule {
    private final String packageName;
    private final Set<Class<? extends Annotation>> bindingAnnotations;

    @SafeVarargs
    public ComponentScanModule(String packageName, final Class<? extends Annotation>... bindingAnnotations) {
        this.packageName = packageName;
        this.bindingAnnotations = new HashSet<>(Arrays.asList(bindingAnnotations));
    }

    @Override
    public void configure() {
        Reflections packageReflections = new Reflections(packageName);
        bindingAnnotations.stream()
            .map(packageReflections::getTypesAnnotatedWith)
            .flatMap(Set::stream)
            .forEach(this::bind);
    }
}

To component scan a package like com.foo and sub packages for classes carrying @Singleton, use it in this way:

public class AppModule extends AbstractModule {
   public void configure() {
     install(new ComponentScanModule("com.foo", Singleton.class));
   }
}
like image 74
leon Avatar answered Sep 30 '22 03:09

leon