简体   繁体   中英

Spring Jersey to inject ContainerRequestContext on request scoped class

I already looked at a lot of posts and nothing seems to work quite as i liked it to.

I want to inject an object into ContainerRequestContext properties from a filter and retrieve it later in other classes.

here is my filter:

@Priority(Priorities.AUTHENTICATION)
public class AuthorizationFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext containerRequestContext) throws IOException {

        containerRequestContext.setProperty("myObject", new Object());
    }
}

here is the class I want access to ContainerRequestContext:

@Provider
public class SessionContextProvider implements ISessionContextProvider {
    @Context
    private ContainerRequestContext request;

    @Override
    public Object getSessionContext() {
        return request.getProperty("mySessionContext");
    }
}

and my spring config:

@Bean(name="sessionContextProvider")
@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
public ISessionContextProvider sessionContextProvider() {
    return new SessionContextProvider();
}

Everything works as expected if I inject ContainerRequestContext into my web resource. However if call my provider class ContainerRequestContext is always null.

I don't seem why this would not work.

Reagrds Jonas

The problem is that with the Jersey/Spring integration, it allows us to successfully inject Spring beans into Jersey components, but this is not always true the other way around.

Jersey has it's own DI framework, HK2 1 , and it is responsible for handle the injections with Jersey components. With the Jersey Spring integration, Jersey will lookup the Spring Bean, and take it as is, it won't inject it with any dependencies, I guess assuming Spring should take care of it's own injections.

That being said, if you don't require the ISessionContextProvider to be a Spring bean, then you can just make it an HK2 service. It's pretty simple. If you don't require any special initialization, you can just let HK2 create it. Here a simple configuration

public JerseyConfig extends ResourceConfig {
    public JerseyConfig() {
        register(new AbstractBinder() {
            bind(SessionContextProvider.class)
                    .to(ISessionContextProvider.class)
                    .in(RequestScoped.class);
        });
    }
}

And that's it. You have an injectable ISessionContextProvider 2 .

If you require the ISessionContextProvider provider to be a Spring bean, then another option is to grab the bean from the Spring ApplicatinContext , and explicitly inject it yourself, using HK2's analogue of the ApplicationContext , its ServiceLocator . To do that we would need to use a Factory to do all the work transparently, so you can still inject the bean without doing any extra work on the outside

import javax.inject.Inject;
import org.glassfish.hk2.api.Factory;
import org.glassfish.hk2.api.ServiceLocator;
import org.springframework.context.ApplicationContext;

public class SessionContextProviderFactory 
        implements Factory<SessionContextProvider> {

    private final ISessionContextProvider provider;

    @Inject
    public SessionContextProviderFactory(ApplicationContext ctx,
                                         ServiceLocator locator) {
        provider = ctx.getBean(ISessionContextProvider.class);
        locator.inject(provider);
    }

    @Override
    public ISessionContextProvider provide() {
        return provider;
    }

    @Override
    public void dispost(ISessionContextProvider provider) { /* noop */ }
}

Then just register the factory

public JerseyConfig extends ResourceConfig {
    public JerseyConfig() {
        register(new AbstractBinder() {
            bindFactory(SessionContextProviderFactory.class)
                    .to(ISessionContextProvider.class)
                    .in(RequestScoped.class);
        });
    }
}

1 -
2 - See also Dependency injection with Jersey 2.0

I found a workaround. I could inject the Spring HttpServletRequest into my AuthorizationFilter and set the SessionContext on this one.

@Autowired
private HttpServletRequest request;

....

request.setAttribute("mySessionContext", sessionContext);

And then because HttpServletRequest is known to spring and besically represents the same thing in my SessionContextProvider I do the same:

@Autowired
private HttpServletRequest request;

@Override
public SessionContext getSessionContext() {
    return (SessionContext) request.getAttribute("mySessionContext");
}

I dont think this is the best solution possible. But it works. Ill wait for peeskillet for any other input if there is a better solution.

Regards Jonas

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM