3

Answer:

Much thanks to all who looked at this, but especially to @Andbdrew. Based on his help I have it working, code at https://github.com/dabraham02124/injection/tree/feature . I'm going to see if I can make it less "annotations do magic", and actually have code call other code, but it's working on the "feature" branch.


Original Question:

I'm trying to inject a resource in a jersey 2.7 application. It isn't working. I'm getting the following error:

2019-04-20 22:06:06,004 WARN [qtp1142020464-16] o.e.j.s.ServletHandler - javax.servlet.ServletException: A MultiException has 3 exceptions. They are: 1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=StringHolder,parent=EntryPoint,qualifiers={}),position=-1,optional=false,self=false,unqualified=null,1295211193) 2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of org.sweatshop.injection.EntryPoint errors were found 3. java.lang.IllegalStateException: Unable to perform operation: resolve on org.sweatshop.injection.EntryPoint

I've followed everything that I see in all the tutorials, for example, but not limited to;

I've tried adding various annotations in various places, I've read all the stackoverflow pages I could find on this, I don't see anything changing.

The minimal example can be found at https://github.com/dabraham02124/injection . The first commit doesn't have injection, and it works. The second commit does have injection and throws.

For those who want to see the code on this page, here's the bits I think are important:

Resource class

@Path("/")
@RequestScoped
public class EntryPoint {
    @Inject
    public StringHolder stringHolder;

    @GET
    @Produces(MediaType.TEXT_HTML)
    public Response homePage() {
        return Response.ok(stringHolder.getString()).build();
    }
}

App class

@ApplicationPath("/")
public class App extends ResourceConfig {
    private final MyServer jettyServer;
    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(App.class);

    public App(MyServer jettyServer) {
        this.jettyServer = jettyServer;
    }

    public static void main(String[] args) throws Exception {
        final ServletContextHandler context = getContext();
        final MyServer jettyServer = new MyServer(8080, context);
        prepJettyServlet(context);

        log.info("about to start up");
        new App(jettyServer).runServer();
    }

    private void register() {
        log.info("start register");

        register(EntryPoint.class);
        register(StringHolder.class);
        register(new AbstractBinder() {
            @Override
            protected void configure() {
                log.info("start bind singleton"); //These three lines never get called
                bind(new StringHolder("injected string")).to(StringHolder.class);
                log.info("end bind singleton");
            }
        });

        log.info("end register");
    }

Injected singleton class

@RequestScoped
public class StringHolder {

    private final String string;

    public StringHolder(String string) {
        this.string = string;
    }

    public String getString() {
        return string;
    }
}

Interestingly, the log shows me calling register on the Binder, but I never see evidence that configure is being called.

Help? I'm pulling my hair out and I'm already bald...

user3742898
  • 343
  • 1
  • 2
  • 9
  • Can you put together a [MCVE], including all dependencies, import statements, and complete code we can copy->paste->run. – Paul Samsotha Apr 21 '19 at 20:18
  • I'm sorry, I thought that I had done that. "The minimal example can be found at https://github.com/dabraham02124/injection . The first commit doesn't have injection, and it works. The second commit does have injection and throws." The readme describes how to build, run, and test. Is there something that I missed? – user3742898 Apr 22 '19 at 12:26
  • I only see 1 commit in that project – Andbdrew Apr 22 '19 at 16:07
  • Oh sorry, I didn't see that link. – Paul Samsotha Apr 22 '19 at 18:54
  • All of the registration should be done _inside_ the constructor of the ResourceConfig subclass, not in some method that gets called after construction. See if that makes any difference. Also you should be using the Jersey AbstractBinder, not the HK2 one. Look at the import statements. – Paul Samsotha Apr 22 '19 at 18:57
  • My apologies re: the commits. – user3742898 Apr 22 '19 at 20:23

1 Answers1

2

You can use a Feature to accomplish this as noted in this answer ( I couldn't make their first approach go with your version of jersey).

@Provider
public final class StartupListener implements Feature {

    private final ServiceLocator serviceLocator;

    @Inject
    public StartupListener(ServiceLocator serviceLocator) {
        this.serviceLocator = serviceLocator;
    }

    @Override
    public boolean configure(FeatureContext context) {
        ServiceLocatorUtilities.bind(serviceLocator, new AbstractBinder() {
            @Override
            protected void configure() {
                bind(new StringHolder("injected string")).to(StringHolder.class);
            }
        });
        return true;
    }
}
Andbdrew
  • 11,788
  • 4
  • 33
  • 37