Search code examples
javajersey

Access to HttpServletContext or session from javax.ws.rs.core.Feature


Context

I am migrating an old legacy jersey application to use a more up-to-date version(2.27).

The application uses jetty servlet to process the authentication and set login information inside the HttpSession.

Then we have some plugins that use jersey and receive the authentication token from an annotation (@SdnUser).

The application is big, and I'd like to avoid the migration process of the authentication method.

Before the migration

I was using an abstract binder linked to an AbstractValueFactoryProvider that provided an AbstractContainerRequestValueFactory.

This AbstractContainerRequestValueFactory gave me access to a RessourceContext where I could get the HttpSession.

    private static final class IdentityParamValueFactory extends AbstractContainerRequestValueFactory<UserManagement.User> {

        private final UserManagement userManagement;
        @Context
        private ResourceContext context;

        public IdentityParamValueFactory(final UserManagement userManagement) {
            this.userManagement = userManagement;
        }

        public UserManagement.User provide() {
            final HttpServletRequest request = context.getResource(HttpServletRequest.class);
            HttpSession session = request.getSession();
            //... code ommited
    }

Now

I have adapted the code to use a feature and an abstract binder :


public class UserBinder implements Feature {

    private final UserManagement userManagement;

    public UserBinder(final UserManagement userManagement) {
        this.userManagement = userManagement;
    }

    @Override
    public boolean configure(final FeatureContext context) {
        context.register(new AbstractBinder() {

            @Context
            private HttpServletRequest webRequest;

            @Override
            protected void configure() {
                UserValueParamProvider userValueParamProvider = new UserValueParamProvider(userManagement, webRequest);
                bind(userValueParamProvider)
                        .to(ValueParamProvider.class)
                        .in(RequestScoped.class);
            }
        });

        return true;
    }

    public static class UserValueParamProvider implements ValueParamProvider {

        // SLF4J Logger
        private static final Logger LOG = LoggerFactory.getLogger(UserBinder.class);

        private final UserManagement userManagement;

        private HttpServletRequest webRequest;

        private UserValueParamProvider(final UserManagement userManagement, HttpServletRequest webRequest) {
            this.userManagement = userManagement;
            this.webRequest = webRequest;
        }

        @Override
        public Function<ContainerRequest, UserManagement.User> getValueProvider(final Parameter parameter) {
            if (parameter.getRawType().equals(UserManagement.User.class)
                    && parameter.isAnnotationPresent(SdnUser.class)) {
                return context -> {
                    ContainerRequest containerRequest = (ContainerRequest) context.getRequest();
                    // The next line is invalid, as the request is a ContainerRequest not an HttpServletRequest
                    HttpServletRequest request = (HttpServletRequest) context.getRequest();
                    HttpSession session = request.getSession();
// ... code ommited

But the functional return of getValueProvider has no context injection, and I cannot reach the HttpSession.

How can I access the HttpSession inside my annotation binder ?


Solution

  • Inject javax.inject.Provider<HttpServletRequest>. Pass the provider into the Function constructor and call provider.get() in the Funtion#apply() method. Provider is used for lazy retrieval. You need to use it in this case because there is no request on startup.